【问题标题】:How can I apply make a default constructor conditionally explicit?如何应用使默认构造函数有条件地显式?
【发布时间】:2019-04-28 10:51:26
【问题描述】:

问题

假设我们有一个(虚构的)类模板C<T>,它带有一个条件显式的默认构造函数。当且仅当std::is_same_v<T, int> 时,默认构造函数应该是显式的。

A search on "[c++] conditionally explicit" 返回此结果:Constructor conditionally marked explicit

一个失败的解决方案

接受的答案举了一个例子:

struct S {
  template <typename T,
             typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
  S(T) {}

  template <typename T,
            typename std::enable_if<!std::is_integral<T>::value, bool>::type = false>
  explicit S(T) {}
};

稍微修改示例给出了这个使用熟悉的方法std::enable_if的实现:

template <class T>
class C {
public:
  template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
  C() {}

  template <std::enable_if_t<!std::is_same_v<T, int>, int> = 0>
  explicit C() {}
};

不幸的是,这甚至无法编译:demo

prog.cc: In instantiation of 'class C<int>':
prog.cc:15:10:   required from here
prog.cc:10:12: error: no type named 'type' in 'struct std::enable_if<false, int>'
   10 |   explicit C() {}
      |            ^
prog.cc: In instantiation of 'class C<double>':
prog.cc:18:13:   required from here
prog.cc:7:3: error: no type named 'type' in 'struct std::enable_if<false, int>'
    7 |   C() {}
      |   ^

问题似乎是由于构造函数的模板参数遗漏,禁用了SFINAE造成的。

问题

  1. 为什么不能编译?
  2. 什么是可能的实现方式?

如果可能,我想避免专攻该课程。

【问题讨论】:

  • c++20 中有一个选项可以向显式添加条件
  • @BiagioFesta 谢谢!你的解决方案对我有用。你能写一个答案并解释细节以便我接受吗?
  • SFINAE 仅在依赖于模板参数时才有效。
  • @PasserBy 感谢“SFINAE 仅在它依赖于模板参数时才有效”这句话!我想这就是我正在寻找的解释。

标签: c++ templates template-meta-programming sfinae explicit


【解决方案1】:
  1. 什么是可能的实现方式?

你试过了吗

template <class T>
class C {
public: //  VVVVVVVVVVVVVV .................................V  U here, not T
  template <typename U = T, std::enable_if_t<std::is_same_v<U, int>, int> = 0>
  C() {}

  template <typename U = T, std::enable_if_t<!std::is_same_v<U, int>, int> = 0>
  explicit C() {}
};

?

  1. 为什么不能编译?

问题在于,SFINAE 通过类方法使用方法本身的模板参数。

这是在原始工作代码中:

  template <typename T,
             typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
  S(T) {}

其中T 是特定于构造函数的模板参数(从单个参数推导出来)。

相反,在你失败的代码中,

template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
C() {}

构造函数正在评估类的模板参数 (T),而不是方法。

使用技巧typename U = T,您将T(类的模板参数)转换为U(方法的模板参数)(在您的情况下为构造函数,但也适用于其他方法)所以@987654329 @,通过基于 U 的测试,能够启用/禁用构造函数。

【讨论】:

  • 感谢您的详细解释!我不得不承认,C++ 模板元编程有时非常违反直觉......
  • @L.F. - 这没什么:如果你尝试使用typename = std::enable_if_t&lt;!std::is_same_v&lt;U, int&gt; 而不是std::enable_if_t&lt;!std::is_same_v&lt;U, int&gt;, int&gt; = 0 启用/禁用两个构造函数,你应该会得到一个错误,因为构造函数发生冲突。
  • 是的,没错。我想这更常见,所以我碰巧知道。
猜你喜欢
  • 2012-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-05
  • 1970-01-01
  • 2011-02-19
  • 2016-06-24
相关资源
最近更新 更多