32

更新: 条件显式已进入 C++20 草案。更多关于 cppreference

cppreference std::tuple 构造函数页面有一堆 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) {}
4

2 回答 2

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;
};

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

正如 Praetorian 指出的那样,这正是libstdc++ 实现它的方式。

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

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) {}
};
于 2015-10-07T17:50:21.573 回答
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 编译。

于 2015-10-07T18:04:08.087 回答