使用不同的enable_if条件选择成员函数

Dav*_*ria 15 c++ templates specialization sfinae c++11

我试图根据类模板参数确定调用哪个版本的成员函数.我试过这个:

#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();
}
Run Code Online (Sandbox Code Playgroud)

我认为这是说"如果T是int,则使用第一个MyFunction,如果T不是int,则使用第二个MyFunction,但我得到编译器错误"错误:'struct std :: enable_if'中没有类型名为'type'谁能指出我在这里做错了什么?

Pra*_*ian 17

enable_if因为模板参数替换导致错误,并且从重载决策集中删除了替换,并且编译器仅考虑其他可行的重载.

在您的示例中,实例化成员函数时不会发生替换,因为当时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;
  }
};
Run Code Online (Sandbox Code Playgroud)

编辑:

正如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;
  }
};
Run Code Online (Sandbox Code Playgroud)

  • @Nawaz:C++ 11标准究竟在哪里说你再也不能这样做了?这是一个非常大胆的改变,IMO,我不明白为什么他们应该这样做.此外,如果它是真的,(现在)惯用的`模板<class T> auto f(T&v) - > decltype(v.foo());`SFINAE构造,它检查成员,将不起作用. (5认同)
  • @Nawaz:这并不意味着返回类型中的替换不再是软错误.另一个线程中的问题是`meta <int>`的*inside*,你得到错误,这在`enable_if`中永远不会发生. (5认同)
  • @Praetorian也许你可以添加`static_assert(std::is_same&lt;U, T&gt;::value, "不要指定模板参数!");`来中断编译。可变参数只是提供更多信息的错误消息(其中的正确类型)。 (2认同)

Naw*_*waz 5

一个简单的解决方案是使用委托来处理私有函数:

template<typename T>
struct Point
{

  void MyFunction()
  {
     worker(static_cast<T*>(nullptr)); //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;
  }
};
Run Code Online (Sandbox Code Playgroud)

Tis 时intworker将调用第一个函数,因为static_cast<T*>(0)结果是 类型int*。在所有其他情况下,将调用 worker 的模板版本。

  • static_cast&lt;T*&gt;(nullptr) (3认同)