2013-08-31 36 views
5

Tôi có một lời tuyên bố về phía trước của một lớp mẫu trong một namespace lồng nhauTuyên bố chuyển tiếp của lớp mẫu trong không gian tên lồng nhau: đối số mẫu mặc định sẽ đi đâu?

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S> 
     struct A; 
    } 
    using n2::A; 
} 

theo sau là một định nghĩa, mà trong thực tế là trong một tập tin khác nhau, với các công cụ ở giữa:

struct X { }; 

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S = X> 
     struct A { }; 
    } 
    using n2::A; 
} 

Sau đó, sau đây là luôn ok:

n1::n2::A <int> a; 

nhưng shortcut này

n1::A <int> a; 

đưa ra một lỗi biên dịch trong vang

error: too few template arguments for class template 'A' 

trừ khi tôi loại bỏ các tuyên bố về phía trước; g ++ chấp nhận cả hai.

clang dường như ở lại với tuyên bố đầu tiên không bao gồm đối số mẫu mặc định (và tôi không thể bao gồm nó vì tôi chưa xác định X).

Không có vấn đề gì nếu tôi sử dụng một không gian tên duy nhất (nhưng đây không phải là giải pháp).

Tôi đang làm gì sai, hoặc trình biên dịch nào là chính xác? Phím tắt hoạt động cùng với khai báo chuyển tiếp và không gian tên lồng nhau như thế nào? Tôi cần tất cả chúng.

Chuyển tiếp khai báo X + đối số mặc định cho S của khóa học, nhưng sẽ quá tẻ nhạt (có hàng tá chúng thực sự và toàn bộ cấu trúc tệp sẽ thay đổi).

+0

Thực tế là có những thứ ở giữa và đó là trong một tệp khác không quan trọng đối với tiếng kêu vang. [Live example] (http://coliru.stacked-crooked.com/view?id=fd521dbdf5) – dyp

+0

Và theo [temp.param]/10, vấn đề này không liên quan đến mẫu, vì cơ chế được xác định theo hàm đối số mặc định. [Live example] (http://coliru.stacked-crooked.com/view?id=17873283ec) – dyp

+0

Điều này có thể phức tạp hơn một chút so với tôi nghĩ ban đầu. [dcl.fct.default]/9 thực sự nói rằng mã của bạn nên hoạt động, nhưng có [vấn đề mở] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1551) với * using-declaration * nơi sửa chữa được đề xuất đưa ra một mâu thuẫn với đoạn này và sẽ phá vỡ mã của bạn. – dyp

Trả lời

1

Tôi đã tìm thấy điều này như một cách giải quyết thuận tiện nhất:

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S> 
     struct A; 
    } 

    namespace fwd { using n2::A; } 
} 

// stuff on n1::fwd::A; 

struct X { }; 

namespace n1 
{ 
    namespace n2 
    { 
     template <typename T, typename S = X> 
     struct A { }; 
    } 

    using n2::A; 
} 

Đó là, di chuyển bằng cách sử dụng-khai đầu tiên namespace khác. Giờ đây, 'nội dung' có thể như sau:

namespace n1 
{ 
    namespace stuff 
    { 
     using namespace fwd; 

     template <typename T> 
     struct R /*...*/; 

     template <typename T, typename S> 
     struct R <A <T, S> > /*...*/; 
    } 
} 

sử dụng A mà không có bất kỳ không gian tên nào. Chỉ có một n1 trong dự án của tôi, nhưng rất nhiều n2, vì vậy hãy di chuyển tất cả các khai báo sử dụng chuyển tiếp trong một không gian tên n1::fwd thuận tiện hơn, vì tôi không thể chỉ sử dụng n1.

2

template<class T> using myname = some::templatething<T>;

Sau đó, bạn có thể sử dụng myname

Trong trường hợp của bạn dính vào một template<class T,class S=X> using A = n2::A<T,S>; trong n1

của bạn Chỉ cần viết một viên ngọc của một câu trả lời liên quan đến Symbol not found when using template defined in a library này có btw, có một chi.

Ok nó không được đánh dấu, vì vậy tôi sẽ giúp một số chi tiết!

sẽ không biên dịch

#include <iostream> 

namespace n1 { 
namespace n2 { 
template<class U,class V> struct A; 
} 
template<class U,class V> using A = n2::A<U,V>; 
} 

static n1::A<int,int>* test; 

struct X {}; 
namespace n1 { 
namespace n2 { 
template<class U,class V> struct A {}; 
} 
template<class U,class V=X> using A = n2::A<U,V>; 
} 

static n1::A<int> test2; 


int main(int,char**) { 

    return 0; 
} 

Tại sao? C++ 's 'quy tắc khai đầu tiên'

Dưới đây là đầu ra của trình biên dịch:

make all 
if ! g++ -Isrc -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -MM src/main.cpp >> build/main.o.d ; then rm build/main.o.d ; exit 1 ; fi 
g++ -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -Isrc -c src/main.cpp -o build/main.o 
src/main.cpp:26:17: error: wrong number of template arguments (1, should be 2) 
static n1::A<int> test2; 
       ^
src/main.cpp:13:47: error: provided for ‘template<class U, class V> using A = n1::n2::A<U, V>’ 
template<class U,class V> using A = n2::A<U,V>; 
              ^
src/main.cpp:26:24: error: invalid type in declaration before ‘;’ token 
static n1::A<int> test2; 
         ^
src/main.cpp:16:24: warning: ‘test’ defined but not used [-Wunused-variable] 
static n1::A<int,int>* test; 
         ^
src/main.cpp:26:19: warning: ‘test2’ defined but not used [-Wunused-variable] 
static n1::A<int> test2; 
       ^
make: *** [build/main.o] Error 

rồi nó rên rỉ về biến không sử dụng, đủ công bằng, nhưng nhận thấy nó tham chiếu đến dòng 13, đó là bởi vì nó được sử dụng định nghĩa đầu tiên đối số mẫu mặc định thực sự khá nguyên thủy và tôi không thể báo giá đặc điểm kỹ thuật cho bạn ngay bây giờ. https://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fdefault_args_for_templ_params.htm

có thể cung cấp một số thông tin chi tiết.

Dù sao nhận thấy rằng:

này biên dịch

#include <iostream> 

namespace n1 { 
namespace n2 { 
template<class U,class V> struct A; 
} 
template<class U,class V> using A = n2::A<U,V>; 
} 

static n1::A<int,int>* test; 

struct X {}; 
namespace n1 { 
namespace n2 { 
template<class U,class V> struct A {}; 
} 
template<class U,class V=X> using B = n2::A<U,V>; 
} 

static n1::B<int> test2; 


int main(int,char**) { 

    return 0; 
} 

Bởi vì B không có định nghĩa trước.

sản lượng xây dựng

make all 
if ! g++ -Isrc -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -MM src/main.cpp >> build/main.o.d ; then rm build/main.o.d ; exit 1 ; fi 
g++ -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings -Isrc -c src/main.cpp -o build/main.o 
src/main.cpp:16:24: warning: ‘test’ defined but not used [-Wunused-variable] 
static n1::A<int,int>* test; 
         ^
src/main.cpp:26:19: warning: ‘test2’ defined but not used [-Wunused-variable] 
static n1::B<int> test2; 
       ^
g++ build/main.o -o a.out 

Xem, tốt :)

Ghi với tờ khai phía trước bạn chỉ có thể sử dụng * s và & s (như họ có kích thước đã biết, kích thước cố định Infact) - oh và & & s

Vì vậy, bạn cần nhận được mặc định đó ngay lập tức!

+0

Cảm ơn, Điều này tránh sử dụng thực tế A trong n1 trước khi nó hoàn tất và sử dụng tên * khác * cho khai báo sử dụng; nhưng tôi thấy nó quá phức tạp. Trong thời gian đó, tôi đã xóa tờ khai chuyển tiếp và tuyên bố 'công cụ' sau khi A hoàn thành, mà tôi nghĩ là thiết kế tốt hơn. Nếu tôi thực sự cần nó trong tương lai, và như tôi đã viết trong bình luận của tôi bên dưới câu hỏi, tôi muốn di chuyển việc sử dụng khai báo đến một không gian tên khác thay vì đổi tên nó, do đó tránh các đối số mẫu hoàn toàn - Tôi sẽ thêm một câu trả lời cho cái đó. – iavr

+0

Vấn đề này khác với OP, vì bạn đang sử dụng các khai báo mẫu bí danh ('template < /*...*/ > sử dụng X = /*...*/;') trong khi OP đang sử dụng khai báo bí danh "đơn giản" (không phải mẫu). Các hiệu ứng khác nhau (cả clang ++ và g ++ từ chối nó), và điều này không liên quan gì đến các không gian tên -> [Live example] (http://coliru.stacked-crooked.com/view?id=b6f6a922c2) .Nó có thể liên quan đến [vấn đề mở 1349] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1349). – dyp