2014-12-05 168 views
1

我试图编译以下行的代码和它失败:模板参数推导C++

template <typename T> 
struct InputBlockParameterType { 
    typedef T type; 
}; 

template <typename T, template <typename> class BlockTypeTrait> 
struct BlockParameterImpl { 
    typedef typename BlockTypeTrait<T>::type type; 
}; 

template <typename T> 
struct InputBlockParameter { 
    typedef typename BlockParameterImpl<T, InputBlockParameterType>::type type; 
}; 


struct Functor { 
    template <typename T> 
    bool operator()(typename InputBlockParameter<T>::type p) { 
     return true; 
    } 
}; 

int main() { 
    InputBlockParameter<double>::type arg = 0.0; 

    Functor f; 
    f(arg); 

    return 0; 
} 

该错误是(MSVC 2013):

1>main.cpp(31): error C2783: 'bool Functor::operator()(InputBlockParameter<T>::type)' : could not deduce template argument for 'T' 
1>   main.cpp(21) : see declaration of 'Functor::operator()' 

如果我改变算符到

struct Functor { 
    template <typename T> 
    bool operator()(T p) { 
     return true; 
    } 
}; 

所有事情都按预期编译。

为什么代码的第一个版本不能编译?它是否在标准中定义的某个地方?

+2

'::'左侧的所有内容都是未推演的上下文。 – 2014-12-05 13:01:50

回答

4

扣除仅适用于推导的上下文。

哪个是无用的:X只在X有效时起作用。我可以引用标准,但它只是说“是的,这是行不通的”,难以阅读散文。

想想它的最好方法是编译器只是模式匹配。但是,它不会搜索或尝试反转您编写的任何类型的映射。

foo<T>::type可以做一个图灵完备的计算(最高编译器限制)从Ttype:这样的标准宣布采用T那里是非推断背景下,即使foo类型映射似乎很容易反过来给你。即使我们已经要求它们是Turing complete来编译C++,但是要求编译器去做任意函数并不是一个实际的事情。

编译器将不会转换(除了base和cv剥离和参数衰减),或者在模板类型扣除期间反转类型映射。它只是模式匹配的论据。

它将按照SFINAE目的的类型映射,但理论上这更容易。

如果您可以自己编写逆映射,则可以使用SFINAE和默认参数以及模板类专业化和转发的混合来获得您可能需要的效果。