为什么此依赖类型不计为使用模板参数的专用化

Why does this dependent type not count as specialization using the template argument?

本文关键字:参数 专用 依赖 类型 为什么      更新时间:2023-10-16

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

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

您在不可推导的上下文中使用T,因此编译器即使知道bar<T>::Type的值也无法推断T

假设你写,

foo<double> foodouble;

那么你可能会想,bar在实例化foo时会选择哪个专门针对double?只有当编译器可以确保不存在另一种将double定义为嵌套类型的bar专用化时,这才似乎是合理的,如下所示:

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不再是专业化。它是一个主模板。另请注意,它可能不是您想要的,因为它禁用了除 floatdoublebool 以外的类型参数的类模板的所有实例化;例如,不能使用 foo<int> 。但是,我还注意到您未定义主模板,因此我希望此解决方案符合您的要求。

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

祝你好运...