5

我正在尝试将专业分组在一起以避免多次编写它们。例如,在下面的代码中,我尝试将“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++ 的哪一部分——如果有人知道这一章和经文,我将不胜感激。此外,如果有人知道实现相同目标的另一种方法(重新使用特定类型组的特化,而没有不必要的冗长代码),我也将不胜感激任何建议!

4

2 回答 2

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

T在不可演绎的上下文中使用,因此T即使编译器知道bar<T>::Type.

假设你写,

foo<double> foodouble;

那么你可能会想,实例化时会选择bar哪个专门的?仅当编译器可以确保不存在另一个定义为嵌套类型的特化时,这似乎是合理的,如下所示:doublefoobardouble

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

现在bar<double>::Typebar<int>::Type双方都给double。所以底线是: 可能存在无数个特化bar,所有这些都可能double作为嵌套类型提供,使得编译器无法唯一地推导出bar类模板的模板参数。


您可以将SFINAE用作:

#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,doublebool;以外的类型参数的类模板的所有实例化。例如,您不能使用foo<int>. 但我也注意到您未定义主模板,所以我希望这个解决方案符合您的要求。

于 2012-04-17T05:32:40.633 回答
2

我不认为你正在尝试的是可能的。我在这里发现了一个类似的问题。我没有链接,但是 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

祝你好运...

于 2012-04-17T05:29:01.627 回答