数组衰减为指针和重载分辨率

array decay to pointer and overload resolution

本文关键字:重载 分辨率 指针 衰减 数组      更新时间:2023-10-16

我希望能够在重载分辨率中区分数组和指针:

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
}

到目前为止,我发现的最好的是使用对指针的引用而不是指针:

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
}

这不是完全相同的事情,我想知道是否存在更好的方法

当两个重载都可行时,您需要使第一个重载成为更糟糕的选择。 目前,它们在转换排名上是平局(两者都是"完全匹配"),然后由于首选非模板而打破了平局。

这应该会使转换排名变得更糟:

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

您可以使用 SFINAE。这可能不是最好的方法,但它应该可以正常工作:

//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";}

这是一个活生生的例子。

可以检测到此问题的更通用版本,如下所示。

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
}