【问题标题】:How should I conditionally enable a constructor?我应该如何有条件地启用构造函数?
【发布时间】:2016-02-27 12:54:47
【问题描述】:

我正在尝试实现这样的目标:

template<typename Bar>
class foo
{
public:
    template<class = std::enable_if_t<std::is_constructible<Bar, int>::value>>
    foo(int x)
        : m_bar(x)
    { }

private:
    Bar m_bar;
};

这会产生行为

foo<int> a; // no error
foo<int> b(0); // no error
foo<std::string> c; // no error
foo<std::string> d(0); // error: none of the 3 overloads could convert all the argument types

正如预期的那样。这个解决方案有什么缺点吗?我不喜欢的是,无论哪种情况,foo::foo(int) 都存在。我知道我可以在foo本身的模板参数列表中使用enable_if,并专门针对这两种情况使用foo,但我不想重复通用代码。

那么,这是最好的(或至少是明智的)选择吗?

【问题讨论】:

  • 您的意思是 Bar 而不是 T 吗?或者,您的意思是 class T = Bar, class = std::enable_if...
  • @PiotrSkotnicki 是的,当然。对不起。
  • 目前没有即时上下文,所以它会编译失败而不是“禁用”构造函数
  • 我没有立即看到这里有什么收获。如果 Bar 没有适合 int 的构造函数,则 foo 的构造函数无论如何都无法编译。
  • @SamVarshavchik 它使构造函数对 SFINAE 友好,或者,让我们将调用回退到另一个构造函数

标签: c++ templates c++14 sfinae enable-if


【解决方案1】:

这个方案有什么缺点吗?

目前,替换发生在直接上下文之外,因此,一旦您尝试使用无法用 int 构造的类型实例化 foo,您的方法就会 cause a hard compilation error

要引入直接上下文,您需要一个虚拟参数:

template <typename T = Bar
//                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~v
        , typename = std::enable_if_t<std::is_constructible<T, int>::value>>
foo(int x)
    : m_bar(x)
{ }

DEMO

【讨论】:

  • 虽然我不确定这是否是您最关心的问题
  • 我已经编辑了问题并在问题中添加了代码的示例用法。 “一旦您尝试使用无法使用int 构造的类型来实例化foo,您的方法就会导致硬编译错误”。这似乎是错误的。除非我尝试使用带有int 参数的构造函数,否则不会发生编译错误。这就是我们想要的行为,不是吗?
  • @0xbadf00d 不,我添加了演示
  • @0xbadf00d Visual C++ 不是符合参考标准的 C++ 编译器,这种行为可能是实现质量的情况。允许编译器拒绝无法生成有效特化的模板
  • 是的,你是对的,我注意到你的解决方案解决了问题。目前有没有更优雅的方式?
猜你喜欢
  • 2011-07-18
  • 1970-01-01
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
  • 2012-05-05
  • 2015-01-20
  • 1970-01-01
相关资源
最近更新 更多