2016-09-20 112 views
1

为什么编译器可以推断T搭配验证码:C++模板参数推演失败

#include <vector> 

template<typename T> 
void foo(T& t) {} 

int main(void) { 
    std::vector<uint8_t> vec = { 1,2,3 }; 
    foo(vec); 
    return 0; 
} 

但没有与此代码:

#include <vector> 
#include <type_traits> 

template<typename T> 
void foo(typename std::enable_if<true, T>::type& t) {} 

int main(void) { 
    std::vector<uint8_t> vec = { 1,2,3 }; 
    foo(vec); 
    return 0; 
} 

我想用第二个结构,两个模板功能之间进行选择,基于传递的类方法存在。

+2

可能存在专门化'std :: enable_if ',其中包含'using type = std :: vector '。编译器如何知道它何时只有参数类型? –

回答

4

正如vsoftco解释,你有一个非推断上下文。

对于SFINAE,你可以使用下列之一:

template<typename T> 
std::enable_if_t<condition_dependent_of_T, ReturnType> 
foo(T& t) {} 

template<typename T, std::enable_if_t<condition_dependent_of_T>* = nullptr> 
ReturnType foo(T& t) {} 
+0

它很好用。但我不明白为什么condition_dependent_of_T必须真正依赖于T.当我在那里评估常量时,代码无法编译,为什么? – omicronns

+2

@omicronns'T'从参数'T&t'中推导出来,而不是从'enable_if'中推导出来的。非推导的上下文是不可推论的,因为编译器从它们推导出类型非常困难(有时不可能)。 'enable_if' **应该**依赖于'T',因为'T'会被推断出来,然后SFINAE将会踢入。 – vsoftco

+0

@ Jarod42我希望可以在SO上合并答案:) – vsoftco

6

在第二种情况下,您有一个non-deduced context,换句话说,编译器无法推断出类型。

非推断上下文的最简单的例子是

template<typename T> 
struct Id 
{ 
    using type = T; 
}; 

template<typename T> 
void foo(typename Id<T>::type arg); // T cannot be deduced 
+2

为了解决这个问题,需要分离扣除和enable_if的上下文。通常的做法是在函数返回值中使用enable_if,如下所示:'template typename std :: enable_if > :: value,void> :: type foo(T&t ){}' –

2

形象化的问题,让我们来分析一个例子:

template <class> 
struct foo { 
    using type = float; 
}; 

template <> 
struct foo<bool> { 
    using type = int; 
}; 

template <> 
struct foo<int> { 
    using type = int; 
}; 

template <class T> 
void bar(foo<T>::type t) { } 

int main() { 
    bar(int{}); 
} 

现在行bar(int{});两种类型bool以及int匹配一个温度迟参数T。那么应该推导出哪一个值?这仅仅是为什么非推断上下文是绝对必要的唯一例子!

+1

upvoted为非常好的例子! – vsoftco

+0

好的。但编译器通过酒吧电话知道那些模棱两可的专业化。当foo 不存在(或foo )时,则没有歧义。 – omicronns

+1

@omicronns是的,但是想象一下,有多少规则和例外需要被添加到一组已经超级复杂的规则中。有时编译器可能不知道:如果您的专业化是在不同的编译单元中定义的,那该怎么办?编译器没有对其他单位作出任何假设。 – vsoftco