C++ 模板参数限制为 类(不是基本类型)

C++ template argument limited to classes (not basic types)

是否可以指定一个永远不会匹配基本类型(例如 int)的模板参数?我正在与歧义作斗争。例如:

template<class T> void Function(const T& x) { SetString(x.GetString()); };

只有在 T 中有 GetString 方法时才有效,但如果编译器看到此函数,它会尝试使用它,例如即使 T 只是 int。

方法一

您可以使用 std::enable_if 如下所示:

C++11

//this function template will not be used with fundamental types
template<class T> typename std::enable_if<!std::is_fundamental<T>::value>::type Function(const T& x) 
{ 
    SetString(x.GetString()); 
    
};

Demo

C++17

template<class T> typename std::enable_if_t<!std::is_fundamental_v<T>> Function(const T& x) 
{ 
    SetString(x.GetString()); 
    
};

Demo

方法二

我们可以利用SFINAE。这里我们使用decltype逗号运算符来定义函数模板的return类型

//this function template will work if the class type has a const member function named GetString
template <typename T> auto Function (T const & x) -> decltype( x.GetString(), void()) 
{ 
    SetString(x.GetString());   
};

Demo

这里我们使用了尾随return类型语法来指定函数模板的return类型。

如果 int 不支持 GetString() 方法的问题,也许不是禁用基本类型的功能,您可以在(且仅当)模板类型时启用它有一个 GetString() const 方法接受不带参数的调用。

观察GetString()一定是const,因为Function()收到一个const引用,所以可以在Function()里面调用GetString()仅当 GetString()const 方法时。

下面是一个完整的编译示例。观察 bar1bar2 情况下的失败情况

#include <string>

void SetString (std::string const &) 
{ }

struct foo // class with a conformat GetString method
{ std::string GetString () const { return "abc"; } };

struct bar1 // class with a not conformant (not const) GetString method
{ std::string GetString () { return "123"; } };

struct bar2 // class with a not conformant (require a int) GetString method
{ std::string GetString (int) const { return "123"; } };

struct bar3 // class without a GetString method
{ };


template <typename T>
auto Function (T const & x) -> decltype( x.GetString(), void())
{ SetString(x.GetString()); }

int main()
{
  Function(foo{}); // compile

  // Function(bar1{}); // compilation error (GetString isn't const)
  // Function(bar2{}); // compilation error (GetString require a int)
  // Function(bar3{}); // compilation error (no GetString method)
  // Function(0);      // compilation error (no GetString method)
}