回退可变构造函数-为什么这样做
Fallback variadic constructor - why does this work?
在回答关于尝试构造可变转发引用构造函数的问题时,只有在没有其他有效构造函数时才应该调用该构造函数。也就是说,如果有:
C(const char*, size_t) { } // 1
template <typename... T, ???> C(T&&... ) { } // 2
我们希望C c1{"abc", 2};
调用(1),尽管需要转换,但C c2{1, 2, 3};
调用(2),因为(1)不适用。
我提出了以下解决方案:
template <typename... T,
typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value>
>
C(T&&... ) { }
提议,我的意思是,我尝试过,并惊讶地发现它确实有效。它的编译和运行完全符合我对gcc和clang的期望。然而,我无法解释为什么可以工作,或者即使实际上应该可以工作,而gcc和clang都特别适合。是吗?为什么?
你的代码的问题是,我们刚刚实例化is_constructible
在上下文中,其中它得到错误的答案。模板代码中的任何类型的缓存都可能导致错误——在调用构造函数之后,尝试在相同的参数上打印is_constructible
!这很可能是错误的。
如何出错的一个活生生的例子。注意,它声明不能从int&
构造C
,尽管在前一行已经这样做了。
struct C {
C(const char*, size_t) {}
template <class... Ts,
typename = std::enable_if_t<!std::is_constructible<C, Ts&&...>::value>
>
C(Ts&&... ) { }
};
int main() {
int a = 0;
C x{a};
std::cout << std::is_constructible<C, int&>{} << 'n';
}
哦。
我怀疑这可能违反了ODR——is_constructible
的两个定义在不同的位置有不同的类型?或者不是。
没有此问题的原始问题的解决方案也已发布。
相关文章:
- 为什么C++的文件 I/O 在读取文本文件时忽略初始空行?我怎样才能让它不这样做?
- 为什么在C++中对链表这样做?(像堆叠一样处理它们)
- C++ 如果在 if 为 true 之后运行,为什么还会这样做
- 为什么 arr[i++] 与 arr[i]++ 会这样做?
- std::字符串 's' 通过 '&s[0]' 转换为字符* - 如何/为什么这样做?
- C++子字符串为什么这样做
- C++循环、作用域和堆栈(为什么这样做?
- 为什么这样做?C中的字符指针
- C++中的字符串分配:为什么这样做
- 带有1个参数的C++2D数组索引(为什么这样做?)
- 为什么这样做?[C++;无效指针]
- 线程之间的Qt连接类型:为什么这样做
- 在派生类中同时分配多个字段-为什么这样做有效
- 为什么这样做?阵列访问不正常
- 迭代char**为什么这样做
- c++ lambda, capture, Smart Ptrs和Stack:为什么这样做?
- 在信号代码中将整数转换为函数指针-为什么这样做?
- 如果一个引用一旦被初始化为一个对象,它就不能被改变,为什么这样做呢?
- 回退可变构造函数-为什么这样做
- 访问类中的私有成员变量:为什么这样做