构造函数有条件地标记为显式

Rya*_*ing 32 c++ c++17

更新: 条件显式使其成为C++ 20草案.更多关于cppreference

cppreference的std ::元组构造页面有一堆的C++ 17的笔记说这样的话:

这个构造函数是explicitif和only if std::is_convertible<const Ti&, Ti>::value至少为falsei

如何编写有条件显式的构造函数?想到的第一种可能性是,explicit(true)但这不是合法的语法.

尝试enable_if失败:

// constructor is explicit if T is not integral
struct S {
  template <typename T,
            typename = typename std::enable_if<std::is_integral<T>::value>::type>
  S(T) {}

  template <typename T,
            typename = typename std::enable_if<!std::is_integral<T>::value>::type>
  explicit S(T) {}
};
Run Code Online (Sandbox Code Playgroud)

有错误:

error: ‘template<class T, class> S::S(T)’ cannot be overloaded
explicit S(T t) {}
Run Code Online (Sandbox Code Playgroud)

Sha*_*our 16

添加N4387:改进对和元组,修订版3的提案有一个如何工作的例子:

考虑以下类模板A,它将用作其他类型T的包装器:

#include <type_traits>
#include <utility>

template<class T>
struct A {
  template<class U,
    typename std::enable_if<
      std::is_constructible<T, U>::value &&
      std::is_convertible<U, T>::value
    , bool>::type = false
  >
  A(U&& u) : t(std::forward<U>(u)) {}

 template<class U,
    typename std::enable_if<
      std::is_constructible<T, U>::value &&
      !std::is_convertible<U, T>::value
    , bool>::type = false
  >
  explicit A(U&& u) : t(std::forward<U>(u)) {}

  T t;
};
Run Code Online (Sandbox Code Playgroud)

显示的构造函数都使用完美转发,并且它们具有基本相同的签名,除了一个是显式的,另一个不是.此外,它们相互排斥.换句话说:这种组合适用于任何目标类型T和任何参数类型U,就像一个显式或非显式的构造函数(或根本没有构造函数).

正如Praetorian所指出的,这正是libstdc ++如何实现它的.

如果我们相应地修改OP示例,它也可以:

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) {}
};
Run Code Online (Sandbox Code Playgroud)


Bo *_*son 5

一种似乎适用于大多数编译器的方法是在其中一个函数中添加一个伪参数,使它们略有不同.

// constructor is explicit if T is integral

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

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

int main()
{
   S  s1(7);

   S  s2("Hello");    
}
Run Code Online (Sandbox Code Playgroud)

与MSVC 2015一起编译.

  • `typename std :: enable_if <test,int>*= 0`在没有`dummy`的情况下工作. (5认同)