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)
}
