模板参数推导和SFINAE - 使用std :: enable_if

时间:2015-01-19 21:03:48

标签: c++ templates c++11 sfinae template-deduction

我正在尝试过滤传递给重载函数模板的类型。我使用的是Visual Studio 2013.

三部分问题:

  1. 为什么我的编译器无法推断Blorg3
  2. TFoo2(argc)生成编译器错误的原因是否与#1相同?
  3. 有没有办法将模板参数传递给构造函数?
  4. 以下是示例代码:

    #include <type_traits>
    
    #define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type
    #define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type
    
    template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n)  { return n + 1; }
    template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n)  { return *n + 1; }
    template <class T> IFINT(T, int) Blorg2(T n)                { return n + 1; }
    template <class T> IFPTR(T, int) Blorg2(T n)                { return *n + 1; }
    template <class T> int Blorg3(IFINT(T, T) n)                { return n + 1; }
    template <class T> int Blorg3(IFPTR(T, T) n)                { return *n + 1; }
    
    struct TFoo1 {
        template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { }
    };
    struct TFoo2 {
        template <class T> TFoo2(IFINT(T, T) n) { }
    };
    
    int main(int argc, char* argv[])
    {
        Blorg1(argc); // intellisense not happy
        Blorg2(argc);
        Blorg3<int>(argc);  // why cant deduce?
        Blorg1(*argv); // intellisense not happy
        Blorg2(*argv); 
        Blorg3<char*>(*argv); // why cant deduce?
        (void)TFoo1(argc); // intellisense not happy
        (void)TFoo2(argc); // intellisense not happy and !!wont compile!!
        return 0;
    }
    

2 个答案:

答案 0 :(得分:2)

回答关于SFINAE无法工作的原因的1/2:

SFINAE 模板参数扣除在这种情况下不能很好地发挥作用。

或者,他们会这样做,只要你知道发生了正确的命令。

必须保证扣除可以被视为在这种情况下要调用的可能函数。

以下是一种以较不技术的方式来看待这个问题的方法:

  1. 编译器会搜索与您尝试调用的内容匹配的可能功能签名。 [see overload resolution]

  2. 如果找到模板参数,它会查看它是否适用于扣除。

  3. 这就是你遇到问题的原因。这两个事件发生的顺序是SFINAE在Blorg1Blorg2TFoo1上工作的原因,而不是Blorg3TFoo2

    使用Blorg3TFoo2,编译器无法将您传递给模板类型的参数插入,因为它会创建无法解析的循环依赖关系。

    template <class T> int Blorg3(IFINT(T, T) n)                { return n + 1; }
    template <class T> int Blorg3(IFPTR(T, T) n)                { return *n + 1; }
    Blorg3<char*>(*argv); // why cant deduce?
    

    要解决Blorg3中的SFINAE,需要了解T。但是,在SFINAE解决之前,T尚不可知。

    同样适用于TFoo2无效的原因。

    第3部分 - 关于模板和构造函数

    是的,您可以将模板参数传递给构造函数,但前提是您通过演绎来执行此操作,例如TFoo1所做的事情。

    您无法显式将模板参数传递给构造函数。

答案 1 :(得分:1)

  

为什么我的编译器无法推断出Blorg3?

std::enable_if<std::is_pointer<T>::value, R>::type ::type中,T指的是依赖于模板参数R和{{1}}的嵌套名称。这是一个非推导的上下文(§14.8.2.5/ 5),因此编译器不会推导出模板参数。

  

这就是TFoo2(argc)生成编译器错误的原因吗?

是的,构造函数模板必须能够推导出它的模板参数,在这种情况下它不能。

  

是否有语法为构造函数提供模板参数?

不,正如我已经提到过的,你不能明确地这样做,必须推断它们,或者模板参数必须有默认参数。