pan-
pan-

Reputation: 153

How can you make sure that a function with array-to-pointer conversion loses in overload resolution?

I want to be able to differentiate array from pointers in overload resolution :

class string {
public:
        string(const char* c_str);

        template<int N>
        string(const char (&str) [N]);
};


int main() {
        const char* c_str = "foo";
        string foo(c_str);      // ok will call string(const char*)

        string bar("bar");      // call string(const char*) instead of the array version
}

The best I have found so far is to use a reference to the pointer instead of a pointer :

class string {
public:
        string(const char*& c_str);

        template<int N>
        string(const char (&str) [N]);
};


int main() {
        const char* c_str = "foo";
        string foo(c_str);      // ok will call string(const char*)
        string bar("bar");      // ok, will call the array version
}

it's not exactly the same thing and I want to know if a better way exist

Upvotes: 11

Views: 1207

Answers (3)

Sumant
Sumant

Reputation: 4326

A more generic version of this problem could be detected as follows.

template <class T>
void func(T, 
          typename std::enable_if<std::is_pointer<T>::value, void>::type * = 0)
{
  // catch ptr
}

template <class T, int N>
void func(T (&)[N])
{
  //catch array
}

int main(void)
{
  int arr[5];
  char *b = 0;
  func(arr); // catch array
  func(b);   // catch ptr
}

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283634

You need to make the first overload a poorer choice when both are viable. Currently they are a tie on conversion ranking (both are "Exact Match"), and then the tie is broken because non-templates are preferred.

This ought to make the conversion ranking worse:

struct stg
{
    struct cvt { const char* p; cvt(const char* p_p) : p(p_p) {} };

    // matches const char*, but disfavored in overload ranking
    stg(cvt c_str); // use c_str.p inside :(  Or add an implicit conversion

    template<int N>
    stg(const char (&str) [N]);
};

Upvotes: 13

Qaz
Qaz

Reputation: 61910

You can use SFINAE. This might not be the best way, but it should work ok:

//thanks to dyp for further reduction
template<typename T, typename = typename std::enable_if<std::is_same<T, char>::value>::type>
string(const T * const &) {std::cout << "const char *\n";}

template<std::size_t N> //credit to jrok for noticing the unnecessary SFINAE
string(const char(&)[N]) {std::cout << "const char(&)[" << N << "]\n";}

Here's a live example.

Upvotes: 6

Related Questions