Michaelzh
Michaelzh

Reputation: 490

How to define enable_if_t based overloads

I wanted to write a template combination of 2 overloads, as shown in the code below, I wish to do different process on 2 genres of objects. when compile I got these errors:

// Error    C2672   'info': no matching overloaded function found
// and
// // Error C2783   'void info(StrType)': could not deduce template argument for '__formal'

code is:


/// With this commented out, compile fails, while with it uncommented, all cals get 
// in to this void template.
//template<typename T/*,
//typename = void*/>
//void info(T s) {
//
//}

template <typename StrType,
    std::enable_if_t<std::is_convertible_v<std::string, StrType>, bool> = false
>
void info(StrType s) {
    std::cout <<"str: "<< s << std::endl;
}


template<typename IntType,
    std::enable_if_t<std::is_same_v<    
    typename std::remove_reference_t<typename std::remove_cv<IntType>>  , 
    int
    >, bool> = false
>
void info(IntType s) {
    std::cout <<"int: "<< s + s << std::endl;
}

int main() {
    info("31");  // Error   C2672   'info': no matching overloaded function found
// and
// // Error C2783   'void info(StrType)': could not deduce template argument for '__formal'

    info((int)111);  // Same complain as above.
}

I was expecting the output be str: 31 int: 111 but compiling failed, complaining: Error C2672 'info': no matching overloaded function found

Upvotes: 2

Views: 404

Answers (2)

Alan Birtles
Alan Birtles

Reputation: 36399

Using if constexpr could make your code simpler, more compact and more importantly more readable:

#include <type_traits>
#include <iostream>

template < typename T >
void info( T s )
{
    if constexpr( std::is_convertible_v< T, std::string > )
    {
        std::cout <<"str: "<< s << std::endl;
    }
    else if constexpr ( std::is_same_v< std::remove_reference_t< std::remove_cv_t< T > >, int > )
    {
        std::cout <<"int: "<< s + s << std::endl;
    }
    else
    {
        std::cout << "unknown type";
    }
}

int main() {
    info("31"); 
    info((int)111);
    info(1.1);
}

Upvotes: 1

songyuanyao
songyuanyao

Reputation: 172934

Note that for std::is_convertible, the 1st template paraemter is From, the 2nd one is To, so change the template argument order from

template <typename StrType,
    std::enable_if_t<std::is_convertible_v<std::string, StrType>, bool> = false
>
void info(StrType s)

to

template <typename StrType,
    std::enable_if_t<std::is_convertible_v<StrType, std::string>, bool> = false
//                                         ^^^^^^^^^^^^^^^^^^^^
>
void info(StrType s)

For the 2nd overload, you should get the type from std::remove_cv, not to use itself directly; so change

template<typename IntType,
    std::enable_if_t<std::is_same_v<    
    typename std::remove_reference_t<typename std::remove_cv<IntType>>  , 
    int
    >, bool> = false
>
void info(IntType s) {

to

template<typename IntType,
    std::enable_if_t<std::is_same_v<    
    typename std::remove_reference_t<typename std::remove_cv<IntType>::type>  , 
    //                                                               ^^^^^^
    int
    >, bool> = false
>
void info(IntType s) {

or (since C++14)

template<typename IntType,
    std::enable_if_t<std::is_same_v<    
    typename std::remove_reference_t<std::remove_cv_t<IntType>>  , 
    //                                             ^^
    int
    >, bool> = false
>
void info(IntType s) {

LIVE

Upvotes: 4

Related Questions