2012-04-17 23 views
5

Tôi đang cố gắng nhóm các chuyên môn lại với nhau để tránh viết chúng nhiều lần. Ví dụ, trong đoạn code dưới đây, tôi cố gắng chuyên "float" và "double" như một trường hợp thực hiện cho foo :: func(); Sau đó tôi sử dụng một triển khai khác cho "bool".Tại sao loại phụ thuộc này không được tính là chuyên môn bằng cách sử dụng đối số mẫu?

template<typename T> struct foo; 

template<typename T> struct bar; 
template<> struct bar<float> { typedef float Type; }; 
template<> struct bar<double> { typedef double Type; }; 

/* specialize for float and double here */ 
template<typename T> struct foo<typename bar<T>::Type> { 
    static void func() { ... } 
}; 

template<> struct foo<bool> { 
    static void func() { ... } 
}; 

Lỗi này trong GCC 4.4.3. (Đây là một trình biên dịch mục tiêu, bởi vì nó là cổ phiếu cho Ubuntu Server 10.04 LTS, mà bị cáo buộc có hơn ba năm để sống.) Lỗi này là:

foo.cpp:8: error: template parameters not used in partial specialization: 
foo.cpp:8: error:   ‘T’ 

Lỗi đề cập đến chuyên môn đầu tiên của foo (cho " float "và" double. ")

Tôi không thấy phần nào của C++ tôi vi phạm ở đây - nếu có ai biết chương và câu, tôi sẽ đánh giá cao nó. Ngoài ra, nếu ai đó biết cách khác để hoàn thành cùng một mục tiêu (sử dụng lại các chuyên môn cho một số nhóm nhất định, không có mã tiết không cần thiết), tôi cũng đánh giá cao bất kỳ đề xuất nào!

Trả lời

6
template<typename T> struct foo<typename bar<T>::Type> { 
    static void func() { ... } 
}; 

Bạn đang sử dụng T trong ngữ cảnh không thể deducible, do đó trình biên dịch không thể suy ra T ngay cả khi nó biết giá trị của bar<T>::Type.

Giả sử bạn viết,

foo<double> foodouble; 

thì bạn có thể nghĩ rằng, bar mà là chuyên ngành với double sẽ được chọn khi instantiating foo? Điều đó có vẻ hợp lý chỉ khi trình biên dịch có thể chắc chắn rằng có không tồn tại khác chuyên môn của bar trong đó xác định double as type lồng nhau, một cái gì đó như thế này:

template<> struct bar<int> { typedef double Type; }; 

Bây giờ bar<double>::Typebar<int>::Type cả cho double. Vì vậy, dòng dưới cùng là: có thể tồn tại số lượng chuyên môn vô hạn của bar, tất cả đều có thể cung cấp double làm loại lồng nhau, làm cho trình biên dịch không thể độc đáo suy luận đối số mẫu cho bar mẫu lớp.


Bạn có thể sử dụng SFINAE như:

#include <iostream> 

template<typename T> struct bar { typedef void type; }; 
template<> struct bar<float> { typedef bar<float> type; }; 
template<> struct bar<double> { typedef bar<double> type; }; 

template<typename T> 
struct foo : bar<T>::type 
{ 
    static void func() 
    { 
     std::cout << "primary template for float and double" << std::endl; 
    } 
}; 

template<> 
struct foo<bool> 
{ 
    static void func() 
    { 
     std::cout << "specialization for for bool" << std::endl; 
    } 
}; 

int main() 
{ 
    foo<float>::func(); 
    foo<double>::func(); 
    foo<bool>::func(); 
} 

Output (online demo):

primary template for float and double 
primary template for float and double 
specialization for for bool 

Lưu ý rằng struct foo : bar<T>::type không phải là một chuyên môn nữa. Nó là một mẫu chính. Cũng lưu ý rằng nó có thể không phải là những gì bạn muốn, vì nó vô hiệu hóa tất cả các instantiations của mẫu lớp với đối số loại khác hơn float, doublebool; ví dụ: bạn không thể sử dụng foo<int>. Nhưng sau đó tôi cũng lưu ý rằng bạn đã để lại mẫu chính chưa được xác định, vì vậy tôi hy vọng giải pháp này phù hợp với yêu cầu của bạn.

+0

Tôi sẽ rất vui khi nhận được thông báo lỗi "không rõ ràng về mẫu" nếu có nhiều thanh có cùng khai báo Kiểu. Trình biên dịch thực sự có tất cả thông tin cần thiết. Thật kỳ lạ, một người bạn báo cáo rằng tuyên bố này hoạt động trên GCC 4.1 trên MacOS X. Dù sao - cảm ơn cho câu trả lời, và đề nghị làm việc xung quanh. Có vẻ như điều đó có thể hiệu quả với tôi! –

2

Tôi không nghĩ rằng những gì bạn đang cố gắng là có thể. Tôi đã tìm thấy một câu hỏi tương tự here. Tôi không có liên kết, nhưng phần có liên quan của tiêu chuẩn C++ là 14.8.2.5. Dưới đây là một trích dẫn từ phần trên trừ đi các đối số mẫu:

The non-deduced contexts are: 
— The nested-name-specifier of a type that was specified using a qualified-id. 
— A non-type template argument or an array bound in which a subexpression references a template 
parameter. 
— A template parameter used in the parameter type of a function parameter that has a default argument 
that is being used in the call for which argument deduction is being done. 
— A function parameter for which argument deduction cannot be done because the associated function 
argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply: 
— more than one function matches the function parameter type (resulting in an ambiguous deduc- 
tion), or 
— no function matches the function parameter type, or 
— the set of functions supplied as an argument contains one or more function templates. 
— A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter 
does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list 
type. [ Example: 
template<class T> void g(T); 
g({1,2,3}); 
// error: no argument deduced for T 
— end example ] 
— A function parameter pack that does not occur at the end of the parameter-declaration-clause. 

Trong trường hợp của bạn, bạn được quy định cụ thể các loại sử dụng một id đủ điều kiện, vì vậy các lập luận không thể suy luận.

Nếu không cho nó quá nhiều suy nghĩ, như một cách giải quyết nhanh chóng bạn có thể thêm một tham số bool phi Loại thứ hai để foo - một cái gì đó như:

template<typename T, bool is_decimal = false> 
struct foo {...}; // general case 

template<typename T> 
struct foo<T, true> { ... }; // case where T is float or double 

Best of luck ...

+0

Điểm tham chiếu! Nỗi buồn là T được loại trừ một cách rõ ràng, mặc dù (trong trường hợp này) nó có thể được suy luận, và sự mơ hồ hoặc không được phát hiện một cách thích hợp. –

Các vấn đề liên quan