flumpb
flumpb

Reputation: 1776

Argument deduction with template member function and non-template overload

I'm not exactly sure how to pose this question as my knowledge relating to the use of templates is quite shallow, but here goes nothing.

I have a class in which I would like to provide a function template for all numerical values and then this function template call the non-template version that expects an std::string such as the following.

template< class T > void
add_to_header( const std::string &key, const T &val )
{
    add_to_header( key, std::to_string( val ) );
}

virtual void
add_to_header( const header& header );

virtual void
add_to_header( const std::string &key, const std::string &val );

This code compiles cleanly but I lose the ability to make a call with a const char [].

instance.add_to_header( "Example1", 4 ); // successful
instance.add_to_header( "Example2", std::string( "str val" ) ); // successful
instance.add_to_header( "Example3", "Not fun" ); // error - none of the 9 overloads could convert all the argument types

What is the idiomatic way of resolving this issue?

Upvotes: 1

Views: 249

Answers (2)

ecatmur
ecatmur

Reputation: 157324

If you specify in the declaration of add_to_header that it needs to be able to call to_string on its arguments then the template overload will be eliminated through SFINAE:

void add_to_header( const std::string &key, const std::string &val );

template<typename T> auto add_to_header( const std::string &key, const T &val )
-> decltype(std::to_string(val), void())  // uses comma operator
{
    add_to_header( key, std::to_string( val ) );
}

Note that the non-template overload needs to be visible at the syntactic point of the definition of the template's body, so that the call inside the body can see the non-template overload.

Using C++14 constraints, we can replace typename T (or class T) with a constraint that encapsulates the requirement:

template<typename T> constexpr bool ToStringable() {
    using namespace std;
    void to_string(...);
    return is_same<string, decltype(to_string(declval<T>()))>::value;
}

template<ToStringable T>
void add_to_header( const std::string &key, const T &val )
{
    add_to_header( key, std::to_string( val ) );
}

Upvotes: 7

PinkFloyd
PinkFloyd

Reputation: 2183

why do you want to use templates for that ? you could simply overload the add_to_header function...

Upvotes: 0

Related Questions