2012-11-15 32 views
11

我想根据类模板参数来确定调用哪个版本的成员函数。我曾经尝试这样做:使用不同的enable_if条件选择成员函数

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct Point 
{ 
    void MyFunction(typename std::enable_if<std::is_same<T, int>::value, T >::type* = 0) 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    void MyFunction(typename std::enable_if<!std::is_same<T, int>::value, float >::type* = 0) 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

int main() 
{ 
    Point<int> intPoint; 
    intPoint.MyFunction(); 

    Point<float> floatPoint; 
    floatPoint.MyFunction(); 
} 

而且我认为他是说:“使用第一MyFunction的,如果T是int和使用第二的MyFunction如果T不是整数,但我得到的编译器错误说”错误:无类型命名'type'in'struct std :: enable_if'“。任何人都可以指出我在这里做错了什么吗?

+0

相关Q&A:“发生了什么事我SFINAE”(终极版)(HTTP:/ /stackoverflow.com/questions/11531989/what-happened-to-my-sfinae-redux-conditional-template-class-members) – HostileFork

回答

11

enable_if工作原因是substitution of a template argument resulted in an error,所以替代从重载解析集中删除,只有其他可行的重载被编译器考虑。

在你的例子中,没有替换发生ng,因为当时已经知道模板参数T。实现你尝试的最简单的方法是创建一个虚拟模板参数,默认为T并使用它来执行SFINAE。

template<typename T> 
struct Point 
{ 
    template<typename U = T> 
    typename std::enable_if<std::is_same<U, int>::value>::type 
    MyFunction() 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename U = T> 
    typename std::enable_if<std::is_same<U, float>::value>::type 
    MyFunction() 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

编辑:

由于HostileFork在评论中提到,最初的例子离开的用户显式指定模板参数的成员函数,却得到了不正确的结果的可能性。以下应防止成员函数的显式特化编译。

template<typename T> 
struct Point 
{ 
    template<typename... Dummy, typename U = T> 
    typename std::enable_if<std::is_same<U, int>::value>::type 
    MyFunction() 
    { 
    static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!"); 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename... Dummy, typename U = T> 
    typename std::enable_if<std::is_same<U, float>::value>::type 
    MyFunction() 
    { 
    static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!"); 
    std::cout << "T is not int." << std::endl; 
    } 
}; 
+0

在C++ 11中,SFINAE规则已被修改了一点点,因此SFINAE将会不在返回类型上触发。总之,这个答案是错误的。 – Nawaz

+0

@Nawaz在gcc4.7.2上工作得很好,自LWS关闭后无法发布演示链接。 [这是](https://ideone.com/J0j3IK)ideone演示。 – Praetorian

+0

这不是C++ 11-conformant代码的证明。 – Nawaz

1

enable_if仅适用于推断函数模板参数或专门的类模板参数。你在做什么是行不通的,因为显然在固定T = int的情况下,第二个声明是错误的。

这是怎么可以做到:

template <typename T> 
void MyFreeFunction(Point<T> const & p, 
        typename std::enable_if<std::is_same<T, int>::value>::type * = NULL) 
{ 
    std::cout << "T is int" << std::endl; 
} 

// etc. 

int main() 
{ 
    Point<int> ip; 
    MyFreeFunction(ip); 
} 

另一种方法是专门Point各类T,或把上面的免费功能到嵌套成员模板包装(这可能是更“适当的”解决方案)。

+0

我见过这个解决方案,但它似乎真的破坏了代码的可读性。 –

+0

@DavidDoria:原始代码太过于人为制作更适合的建议。 –

+0

@DavidDoria如果你的情况是你只是使用SFINAE来检查某些类型是否是'is_same'(如果那些不匹配,那么它们有一个默认值),那么针对这些固定类型的模板特化'Point'就是你通缉。你会有更可读的定义相同的实例化。 – HostileFork

2

一个简单的解决方案是使用代表团工人私人功能:

template<typename T> 
struct Point 
{ 

    void MyFunction() 
    { 
    worker(static_cast<T*>(0)); //pass null argument of type T* 
    } 

private: 

    void worker(int*) 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename U> 
    void worker(U*) 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

Tint,第一worker函数将被调用,因为static_cast<T*>(0)原来是int*类型。在所有其他情况下,将调用模板版本的工作人员。

+1

我其实很喜欢这个。我不认为我会使用它,但OP的例子是如此人为设计,这确实是一个很好的解决方案。 –

+1

static_cast (nullptr) –

0

基于执政官的建议(但不改变函数的返回类型),这似乎工作:

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct Point 
{ 
    template<typename U = T> 
    void MyFunction(typename std::enable_if<std::is_same<U, int>::value, U >::type* = 0) 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename U = T> 
    void MyFunction(typename std::enable_if<!std::is_same<U, int>::value, float >::type* = 0) 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

int main() 
{ 
    Point<int> intPoint; 
    intPoint.MyFunction(); 

    Point<float> floatPoint; 
    floatPoint.MyFunction(); 
} 
相关问题