后备可变参数构造函数 - 为什么这有效?

Fallback variadic constructor - why does this work?(后备可变参数构造函数 - 为什么这有效?)
本文介绍了后备可变参数构造函数 - 为什么这有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

在回答这个问题时,关于尝试构造一个可变参数转发引用构造函数,只有在没有其他构造函数时才应调用该构造函数有效的.也就是说,如果有:

In answering this question about trying to construct a variadic forwarding reference constructor that should only be called if no other constructor is valid. That is, if there was a:

C(const char*, size_t) { }                     // 1
template <typename... T, ???> C(T&&... ) { }   // 2

我们希望 C c1{"abc", 2}; 调用 (1),尽管需要转换,但是 C c2{1, 2, 3}; 调用 (2),因为 (1) 不适用.

We'd want C c1{"abc", 2}; to call (1), despite the required conversion, but C c2{1, 2, 3}; to call (2), as (1) cannot apply.

我提出了以下解决方案:

I proposed the following solution:

template <typename... T,
          typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value>
           >
C(T&&... ) { }

我的意思是说,我尝试过并惊讶地发现它确实有效.它编译并完成了我对 gcc 和 clang 的期望.但是,我无法解释为什么它起作用,或者即使它实际上应该起作用,而且 gcc 和 clang 都特别包容.是吗?为什么?

And by proposed, I mean, I tried it and was surprised to discover that it actually works. It compiles and does exactly what I had hoped for on both gcc and clang. However, I am at a loss to explain why it works or even if it's actually supposed to work and gcc and clang are both just being particularly accommodating. Is it? Why?

推荐答案

你的代码的问题是我们只是在一个上下文中实例化了 is_constructible它得到了错误的答案.模板代码中的任何类型的缓存都可能导致错误——尝试在调用构造函数后在相同的参数上打印 is_constructible!很可能会弄错.

The issue with your code is that we just instantiated is_constructible in a context where it gets the answer wrong. Any kind of caching in the template code is likely to result in bugs -- try printing is_constructible on the same parameters after you call the constructor! It is likely to get it wrong.

现场示例,说明如何出错.请注意,它声称 C 不能从 int& 构造,尽管在前一行已经这样做了.

Live example of how it can go wrong. Notice it claims C cannot be constructed from an int&, despite having done so on the previous line.

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&>{} << '
';
}

糟糕.

我怀疑这可能是 ODR 违规——is_constructible 的两个定义在不同的位置有不同的类型?或者也许不是.

I suspect this might be an ODR violation -- the two definitions of is_constructible have different types at different spots? Or maybe not.

没有这个问题的原始问题的解决方案也贴出来了.

这篇关于后备可变参数构造函数 - 为什么这有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

How do compilers treat variable length arrays(编译器如何处理变长数组)
Deduce template argument from std::function call signature(从 std::function 调用签名推导出模板参数)
check if member exists using enable_if(使用 enable_if 检查成员是否存在)
Standard Library Containers with additional optional template parameters?(具有附加可选模板参数的标准库容器?)
Uses of a C++ Arithmetic Promotion Header(C++ 算术提升标头的使用)
Parameter pack must be at the end of the parameter list... When and why?(参数包必须位于参数列表的末尾...何时以及为什么?)