Home > other >  C template argument limited to classes (not basic types)
C template argument limited to classes (not basic types)

Time:03-02

Is it possible specify a template argument, that would never match to a basic type, such as an int? I'm heavily fighting ambiguities. So for example:

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

That would work only if there's a method GetString in T, but if the compiler sees this function, it tries to uses it even if T is just int for example.

CodePudding user response:

Method 1

You can use std::enable_if as shown below:

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

Method 2

We can make use of SFINAE. Here we use decltype and the comma operator to define the return type of the function template.

//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

Here we've used trailing return type syntax to specify the return type of the function template.

CodePudding user response:

If the problem i that int doesn't support a GetString() method, maybe instead of disable the function for fundamental types, you could enable it if (and only if) the template type has a GetString() const method accepting a call without arguments.

Observe that GetString() must be const, because Function() receive a const reference, so you can call GetString() inside Function() only if GetString() is a const method.

The following is a full compiling example. Observe the failure in the bar1 and bar2 cases

#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)
}
  • Related