Pap*_*ter 5 c++ templates disambiguation c++11
我有一个将大小作为模板参数的类(live demo):
template <std::size_t SIZE> class A
{
char b[SIZE];
}
Run Code Online (Sandbox Code Playgroud)
它具有用于不同目的的多个构造函数:
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{} {}
Run Code Online (Sandbox Code Playgroud)
使用此构造函数集,此指令没有问题:
// 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);
Run Code Online (Sandbox Code Playgroud)
但是,在调用时A<5>("five")
,构造函数2、3、4和5之间存在模棱两可的调用。
所以我的问题是:
CASE 1
?A<SIZE>
与模板参数大小相同的静态数组构造对象时,是否可以消除构造函数2、3、4、5的歧义?感谢您的关注。
在重载决策期间对转换序列进行排序时,数组到指针的转换被视为完全匹配(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{} {}
Run Code Online (Sandbox Code Playgroud)
但这样做只会导致结构的含糊不清。实际上没有简单的方法来消除歧义const char (&)[]
和const char*
重载:最好的解决方案可能是更改 (3) 以接受指针和长度:
A(const char * const, std::size_t) : b{} {
std::cout << "size: " << SIZE << " ctor 3\n";
}
Run Code Online (Sandbox Code Playgroud)
顺便说一下,我会注意到,size_t
向const char* const
构造函数添加参数也可以消除A("five")
case 的歧义。
编辑:但是,有一种合理的方法可以消除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"; }
Run Code Online (Sandbox Code Playgroud)
[这个特殊技巧的功劳归功于dyp,也可能归功于 Johannes Schaub 或 Yakk 或我(我很确定这不是我)。]
该模板通过引用有效地锁定实际类型(在发生数组到指针转换之前),然后限制对非指针类型的引用。