模板默认类型与默认值

时间:2016-10-26 15:52:18

标签: c++ templates sfinae

此问题遵循previous one

案例1:默认类型

以下程序无法编译并报告select CONCAT(tu.username,' have: ',tm.money,'$') as RESULT from [$table_users] as tu inner join [$table_money] as tm on tu.ID_USER = tm.ID_USER order by RESULT ASC;

error C2995: 'T foo(void)': function template has already been defined

两个#include <iostream> #include <type_traits> template < typename T, typename = std::enable_if_t< std::is_integral<T>::value> > T foo() { std::cout << "integral" << std::endl; return T(); } template < typename T, typename = std::enable_if_t< !std::is_integral<T>::value> > T foo() { std::cout << "non-integral" << std::endl; return T(); } int main() { foo<int>(); foo<float>(); } 实例化中,每个模板都是交替使用和忽略(SFINAE)。所以我假设编译器在某个时刻看到:

foo

两个定义都是相同的,错误在某种程度上是可以理解的。也许不太可以理解为什么编译器此时没有分配不同的内部函数名。

案例2:默认值

现在,程序可以修复,而不是使用默认类型,我们使用默认值:

template < typename T, typename = void >
T foo() { std::cout << "integral" << std::endl; return T(); }

template < typename T, typename = void >
T foo() { std::cout << "non-integral" << std::endl; return T(); }

在这里,按照相同的程序,我推导出:

template < typename T, std::enable_if_t< std::is_integral<T>::value>* = nullptr >
T foo() { std::cout << "integral" << std::endl; return T(); }

template < typename T, std::enable_if_t< !std::is_integral<T>::value>* = nullptr >
T foo() { std::cout << "non-integral" << std::endl; return T(); }

如果这是替代,那么它将具有相同的定义并且不会编译。很明显,编译器没有这样做,或者如果是,它不会停在那里并最终得到类似的东西:

template < typename T, void* = nullptr >
T foo() { std::cout << "integral" << std::endl; return T(); }

template < typename T, void* = nullptr >
T foo() { std::cout << "non-integral" << std::endl; return T(); }

为什么编译器设法在第二种情况下获得两种不同的功能,而不是第一种?

标准为解释模板默认类型与默认值指定了哪种算法?

1 个答案:

答案 0 :(得分:4)

  

在这里,按照相同的程序,我推导出:

直到那一刻,一切都是正确的。你有两个功能模板(忽略默认值):

template < typename T, std::enable_if_t< std::is_integral<T>::value>*>
T foo();

template < typename T, std::enable_if_t< !std::is_integral<T>::value>*>
T foo();

两个非类型模板参数没有类型void*。它们分别具有std::enable_if_t<std::is_integral<T>::value>*std::enable_if_t<!std::is_integral<T>::value>*类型。那些不是同一类型。甚至不存在T,在替换之后,它们是相同的类型。

具体规则在[temp.over.link]:

  

如果两个函数定义包含,则认为涉及模板参数的两个表达式是等效的   表达式将满足单定义规则(3.2),除了用于命名模板的标记   只要用于命名一个表达式中的模板参数的标记替换为参数,参数就可能不同   另一个在另一个表达式中命名相同模板参数的标记。用于判断是否两个   依赖名称(14.6.2)是等价的,只考虑名称本身,而不是名称查找的结果   模板的上下文。

     

如果两个函数模板在同一范围内声明,具有相同的名称,则它们是等效的   相同的模板参数列表,并具有使用相同的返回类型和参数列表   上述规则用于比较涉及模板参数的表达式。两个功能模板是   功能上等价,如果它们是等价的,除了涉及模板的一个或多个表达式   返回类型和参数列表中的参数在功能上等效,使用所描述的规则   上面比较涉及模板参数的表达式。如果程序包含函数声明   功能相同但不相同的模板,程序格式不正确;没有诊断   必需的。

这两个函数没有相同的模板参数列表。