5

我有一个将大小作为模板参数的类(现场演示):

template <std::size_t SIZE> class A
{
    char b[SIZE];
}

它有多个用于不同目的的构造函数:

using const_buffer_t = const char (&)[SIZE];
using my_type = A<SIZE>;

A()                         : b{} {} // (1) no params
A(const_buffer_t)           : b{} {} // (2) copy contents of given buffer
A(const char * const)       : b{} {} // (3) copy as many items as they fit into the size
explicit A(const my_type &) : b{} {} // (4) copy constructor

// (5) copy as many items as they fit into the size
template <std::size_t OTHER_SIZE>
A(const char (&)[OTHER_SIZE]) : b{} {}

// (6) copy constructor from another sized A
// copy as many items as they fit into the size
template <std::size_t OTHER_SIZE>
explicit A(const A<OTHER_SIZE> &) : b{} {}

使用这组构造函数,这个指令没有问题:

// CASE 1
// Calls constructor 3: A<5>(const char * const)
// Expecting constructor 5: A<5>(const char (&)[11])
A<5> a("0123456789");

// CASE 2
// As expected, calls constructor 1: A<5>()
A<5> b();

// CASE 3
// As expected, calls constructor 4: A<5>(const A<5> &)
A<5> c(b);

// CASE 4
// As expected, calls constructor 6: A<5>(const A<9> &)
A<9> c(b);

但是在调用时A<5>("five"),构造函数 2、3、4 和 5 之间存在模棱两可的调用。

所以我的问题是:

  • 为什么构造函数 3 比构造函数 5 更受青睐CASE 1
  • A<SIZE>当使用与模板参数大小相同的静态数组构造对象时,有没有办法消除构造函数 2、3、4、5 的歧义?

感谢您的关注。

4

2 回答 2

4

在重载解析期间对转换序列进行排序时,数组到指针的转换被认为是完全匹配的(C++11 13.3.3.1.1/1 表 12)。与您的直觉相反,这意味着 (3) 和 (5) 对于A<5> a("0123456789");. 正如Xeo 在他的评论中所说的那样,平局被打破了,有利于非模板 (3)。您可能会想通过将 (3) 转换为模板来欺骗编译器:

template <typename=void>
A(const char * const) : b{} {}

但这样做只会导致构造的歧义。确实没有简单的方法来消除歧义const char (&)[]const char*重载:最好的解决方案可能是更改 (3) 以接受指针和长度:

A(const char * const, std::size_t) : b{} {
  std::cout << "size: " << SIZE << " ctor 3\n";
}

顺便说一句,我会注意到向构造函数添加size_t参数也可以消除case的歧义。const char* constA("five")

编辑:但是,有一种合理的方法可以char*从数组构造函数中消除构造函数的歧义,通过引用接受指针参数:

template <typename T,
  typename=typename std::enable_if<
    std::is_same<typename std::remove_cv<T>::type, char>{}
  >::type>
A(T* const&) : b{} { std::cout << "size: " << SIZE << " ctor 3\n"; }

[这个特殊技巧的功劳归于 dyp,可能还有 Johannes Schaub 或 Yakk 或我(我很确定不是我)。]

该模板通过引用有效地锁定实际类型 - 在数组到指针的转换发生之前 - 然后限制对非指针类型的引用。

于 2014-04-25T14:25:03.280 回答
2
  • 为什么在案例 1 中构造函数 3 优于构造函数 5?

    答: 由于重载决议。非模板类函数是一等公民,因此比模板函数具有更高的重载决议等级。因此,构造函数 3 优于模板构造函数 5。

于 2014-04-25T12:04:22.950 回答