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());
};
C 17
template<class T> typename std::enable_if_t<!std::is_fundamental_v<T>> Function(const T& x)
{
SetString(x.GetString());
};
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());
};
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)
}