32

更新: 条件付き明示が C++20 ドラフトに組み込まれました。cppreference の詳細

cppreference std::tuple コンストラクター ページには、次のような C++17 のメモがたくさんあります。

このコンストラクターは、少なくとも 1 つが false であるexplicit場合にのみ使用されます。std::is_convertible<const Ti&, Ti>::valuei

条件付きで明示的なコンストラクターをどのように作成できますか? 頭に浮かんだ最初の可能性は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には、それがどのように機能するかの例があります。

他の型 T のラッパーとして使用することを意図した、次のクラス テンプレート A を考えてみましょう。

#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++ が実装する方法です。

それに応じて 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) {}
};
于 2015-10-07T17:50:21.573 に答える
5

ほとんどのコンパイラで機能するように見える 1 つの方法は、関数の 1 つにダミー パラメータを追加して、それらをわずかに異なるものにすることです。

// 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 に答える