我正在尝试将特化组合在一起,以避免多次编写它们。例如,在下面的代码中,我尝试将“float”和“double”专门化为foo :: func()的一个实现案例;然后我使用另一个实现“bool。”
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() { ... }
};
这在GCC 4.4.3中出错。 (这是一个目标编译器,因为它是Ubuntu Server 10.04 LTS的库存,据称还有三年的生存时间。) 错误是:
foo.cpp:8: error: template parameters not used in partial specialization:
foo.cpp:8: error: ‘T’
错误是指foo的第一个特化(对于“float”和“double”。)
我没有看到我在这里违反C ++的哪个部分 - 如果有人知道章节和经文,我会很感激。 此外,如果有人知道实现相同目标的另一种方式(对某些类型的组重新使用特化,没有不必要的冗长代码),我也会感激任何建议!
答案 0 :(得分:6)
template<typename T> struct foo<typename bar<T>::Type> {
static void func() { ... }
};
您在非可导入的上下文中使用T
,因此即使编译器知道T
的值,编译器也无法推导bar<T>::Type
。
假设你写,
foo<double> foodouble;
那么你可能会认为,在bar
实例化时会选择专门用double
的{{1}}?只有当编译器确保不存在将foo
定义为嵌套类型的bar
的另一个特化时,这似乎是合理的,如下所示:
double
现在template<> struct bar<int> { typedef double Type; };
和bar<double>::Type
都提供bar<int>::Type
。所以底线是:double
可能存在无限数量的专门化,所有这些都可以提供bar
作为嵌套类型,这使得编译器无法唯一推导出double
类模板的模板参数。
您可以将SFINAE用作:
bar
输出(online demo):
#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();
}
请注意primary template for float and double
primary template for float and double
specialization for for bool
不再是专业化了。这是一个主要模板。另请注意,它可能不是您想要的,因为它禁用类型参数的所有实例化,类型参数不是struct foo : bar<T>::type
,float
和double
;例如,您无法使用bool
。但是我还注意到你已经保留了主要模板的未定义,所以我希望这个解决方案符合你的要求。
答案 1 :(得分:2)
我不认为你所尝试的是可能的。我发现了一个类似的问题here。我没有链接,但c ++标准的相关部分是14.8.2.5。以下是关于模板参数推导的部分的引用:
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.
在您的情况下,您使用限定ID指定类型,因此无法推断出该参数。
不要过多考虑,作为快速解决方法,你可以为foo添加第二个非类型bool参数 - 例如:
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
祝您好运......