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

时间:2015-10-07 17:32:03

标签: c++ c++17

更新: conditional explicit已进入C ++ 20草案。 more on cppreference

cppreference std::tuple constructor page有一堆C ++ 17注释说:

  

此构造函数为explicit当且仅当std::is_convertible<const Ti&, Ti>::value对于至少一个i

而言为假

如何编写有条件显式的构造函数?我想到的第一种可能性是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) {}
};

错误:

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

2 个答案:

答案 0 :(得分:14)

添加N4387: Improving pair and tuple, revision 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;
};
     

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

正如Praetorian所指出的那样libstdc++ implements it

如果我们相应地修改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) {}
};

答案 1 :(得分: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");    
}

使用MSVC 2015进行编译。