0

可変個引数テンプレートについて質問があります。次の方法でそれらを使用するクラスがあります。

template <class... T>
struct A {
  A(B& arg);                   // (1)
  A(typename T::B& args...);   // (2)
};

typename T::Bパラメーター パック内のすべてのインスタンスで等しいと予想される型です。プレゼンテーションを簡単にするために、このタイプを と呼びましたB。このクラスにはB、パラメーター パック内の各パラメーターのインスタンスが含まれています。2 番目のコンストラクターは(2)、これらのメンバーを初期化します。便宜上、(1)インスタンスを 1 つだけ取り、すべてのメンバーを同じインスタンスで初期化するコンストラクターがあります。

コンストラクターの定義は、私の問題にとってそれほど重要ではありません。空のままにしておくことができます。より完全な例を以下に示します。

ここで、問題は、A を 1 つのパラメーターだけで初期化すると、コンストラクターが競合することです。g++-4.7はここで少し混乱して救済されましたが、クラスを詳しく見てみると、問題は明らかでした。

質問:

  1. 基準は状況について何と言っていますか? これは、コンパイラによって解決されるべき/可能なあいまいさですか、それともこの状況を回避することになっていますか?

  2. それを回避するための最善の戦略は何ですか?最初のコンストラクターのようなものをまったく指定していませんか? 最初のコンストラクターの機能を静的メソッドに入れることもできますが、そうすると API がより不均一になります。

回答ありがとうございます。


完全な例:

struct B {};

struct C
{
  using B = ::B;
};

template <class... T>
struct A
{
  A(B& arg) {}
  A(typename T::B & ... args) {}
};

int main()
{
  A<C> x(B()); // Edit: Should be: A<C> X{B()}; But not related to the problem.
  return 0;
}
4

1 に答える 1

4
A<C> x(B());

オブジェクト宣言ではなく、関数宣言です。括弧を追加するか、中括弧を使用する必要があります。

A<C> x { B() };

また

A<C> x((B()));

Bまた、参照によってコンストラクターに一時を渡すには、次のようにする必要がありconstます。

A(const B& arg) { }

それで

A<C> x((B()));

正常に動作します。

あいまいさの問題に対処するには、次のようなものが必要です。

#include <type_traits>
#include <iostream>

struct B {};

struct C
{
  using B = ::B;
};

template <class... T>
struct A
{
  A(const B& arg) {
    std::cout << "one" << std::endl;
  }

  template<bool IsNotOne = sizeof...(T) != 1>
  A(const typename std::enable_if<IsNotOne || !std::is_same<B, T>::value, T>::type::B&... args) {
    std::cout << "multiple" << std::endl;
  }
};

int main()
{
  A<B> x1 { B() };         // prints one
  A<C> x2 { B() };         // prints one
  A<C, C> x3 { B(), B() }; // prints multiple
  A<B, B> x4 { B(), B() }; // prints multiple
  return 0;
}

SFINAE に依存できるように、2 番目のコンストラクターをテンプレートにします。

于 2012-10-23T17:11:26.320 に答える