Ryand
Ryand

Reputation: 436

Determine if a type has particular member function signature

template<typename U> struct CheckSignature {
    enum {SizeTrue = 1, SizeFalse = 2};
    typedef char ReturnTrue[SizeTrue];
    typedef char ReturnFalse[SizeFalse];
    typedef typename U::iterator (U::*InsertSig)(typename U::iterator, typename const U::value_type &);
    static ReturnTrue &CheckInsert(InsertSig);
    static ReturnFalse &CheckInsert(...);
    static const bool value = (sizeof(CheckInsert(&U::insert)) == sizeof(ReturnTrue));
};

int main() {
    CheckSignature<std::string >::value; //compile error
    CheckSignature<std::vector<int> >::value; // OK
    return 0;
}

This code generates a compile error for the string class saying that none of the 2 overloads could convert all argument types. However, for vector it compiles fine. Shouldn't overload resolution choose CheckInsert(...) whenever the parameter isn't of type InsertSig?

Upvotes: 2

Views: 250

Answers (2)

Mikael Persson
Mikael Persson

Reputation: 18572

Try this instead:

#include <string>
#include <vector>
#include <iostream>

template<typename U> struct CheckSignature {
    enum {SizeTrue = 1, SizeFalse = 2};
    typedef char ReturnTrue[SizeTrue];
    typedef char ReturnFalse[SizeFalse];
    typedef typename U::iterator (U::*InsertSig)(typename U::iterator, typename U::value_type const &);
    template <InsertSig f> struct dummy_type { };
    template <typename T>
    static ReturnTrue &CheckInsert(T*, dummy_type<&T::insert> dummy = dummy_type<&T::insert>());
    static ReturnFalse &CheckInsert(...);
    static const bool value = (sizeof(CheckInsert(((U*)0))) == sizeof(ReturnTrue));
};

int main() {
    if(CheckSignature<std::string >::value) {
      std::cout << "String class has proper insert function" << std::endl;
    }; //OK, does not print, as expected.
    if(CheckSignature<std::vector<int> >::value) {
      std::cout << "Vector class has proper insert function" << std::endl;
    }; //OK, does print, as expected.
    return 0;
}

The reason why it doesn't work is because, in your version, taking the address of the insert function will fail at the call site, not at the substitution (which is not an error). The above will make sure that if the type U (templated to T) cannot be used to obtain a member function pointer to insert which is convertable to the given signature, it will fail to substitute for the dummy parameter, and thus, revert to the ellipsis version.

Upvotes: 2

Bo Persson
Bo Persson

Reputation: 92271

The std::string::insert doesn't take a const char& parameter, but just a char.

Also, depending on how far the implementation has has come in its C++11 support, all containers might use a const_iterator (instead of iterator) to indicate the position.

Upvotes: 0

Related Questions