0

非常に興味深い問題があります。2 つのテンプレート クラスがあります。1 つは任意のテンプレート パラメータを使用でき、もう 1 つはより特殊化されています (このおもちゃの問題では、浮動小数点を使用する必要があると言います)。

template< class T >
class CanBeAnything{ /*...*/ };

template< class T >
class MustBeFloat{ static_assert(is_floating_point<T>::value, ""); /*...*/ };

これで、別のテンプレート クラス Foo ができました。Foo にはそのテンプレート パラメータに制限がなく、関数 fooは同じ型のaCanBeAnythingまたは aを取ります。MustBeFloatここでは明示的なテンプレートのインスタンス化を使用したいと考えているためMustBeFloat、テンプレート パラメーターが浮動小数点の場合にのみオーバーロードが存在するようにします。

最も簡単な解決策は Foo を特殊化することですが、2 つのクラス間でインターフェイスを複製するという考えは好きではありません。私は、ほぼ機能する CRTP ソリューションを思いつきましたが、すぐに言及する 1 つの問題があります

/* Traits object to get the value_type out of foo */
template<class FooType>
class FooTraits{};

/* Helper parent class with floating-point only methods */
template<class Derived, bool isFloatingPoint>
class FooSpecialization {}

template<class Derived>
class FooSpecialization<Derived, true>
{
   typedef typename FooTraits<Derived>::value_type value_type;
public:
   void foo( MustBeFloat<value_type> & x );
};

/* Front-end interface */
template<class T>
class Foo : public FooSpecialization< Foo<T>, is_floating_point<T>::value >
{
   typedef FooSpecialization< Foo<T>, is_floating_point<T>::value > Parent;
   typedef typename FooTraits< Foo<T> >::value_type value_type;
public:
   void foo( CanBeAnything<value_type> & x );
private:
   friend class Parent;
};

template<class T>
class FooTraits< Foo<T> >
   { public:  typedef T value_type; };

問題は次のとおりです。そのままでは、への呼び出しはfoo( MustBeFloat<value_type> & )名前の非表示によって子クラスに隠され、コンパイラは「メソッド foo への一致する呼び出しがありません」というエラーを表示します。行を追加してダウンさせると、メソッドがそこまで存在しないため、using Parent::foo;非浮動小数点をインスタンス化するときに「親クラスに foo が存在しません」というエラーが表示されます。Foo

何か案は?よりエレガントで実用的なソリューションが利用可能であれば、このソリューション全体をスクレイピングしても問題ありません。

編集: 明確にするために: ここでは明示的なインスタンス化を行っています。そのため、浮動小数点テンプレート パラメーターがある場合にのみメソッドが存在する必要があります。

template class Foo<int>;
template class Foo<float>;

これにより、すべてのクラスメンバーがインスタンス化されるため、特定のメソッドをインスタンス化しないことに依存するメソッドは使用できません。

EDIT2:さて、私はこれを考えていました。これが私が行っている解決策です:

template<class T>
class Foo
{
public:
   template<class T2>
   void foo( MustBeFloat<T2> & x ){ static_assert( std::is_same<T,T2>::value, ""); /* ... */}
   void foo( CanBeAnything<T> & x ){ /* ... */ }
};

template class Foo<int>;
template class Foo<float>;
template void Foo::foo<float>(MustBeFloat<float> &);

そして、それはすべて機能します。わーい!私をこの解決策に導き、他のより独創的な解決策を思いついた人々に感謝します。

4

2 に答える 2

1

これで十分かもしれません:

template <class T, bool isFloat, class Other>
struct FooTraits;
template <class T, class Other>
struct FooTraits<T, true, Other> { typedef MustBeFloat<T> MaybeFloat; };
template <class T, class Other>
struct FooTraits<T, false, Other> { typedef Other MaybeFloat; };

template <class T>
class Foo
{
    template <class U> friend class FooTraits<U>;
    class PrivateType {};
public:
    typedef typename FooTraits<T,
                               std::is_floating_point<T>::value,
                               PrivateType>::MaybeFloat MaybeFloat;
    void foo(CanBeAnything<T>&);
    void foo(MaybeFloat&);
};

Tが浮動小数点の場合、 はMaybeFloatへの typedef になりますMustBeFloat<T>。そうしないと、 のプライベート メンバー クラスにFooなるため、 の呼び出し元がfoo()その型の左辺値を合成することはできません。

于 2014-05-01T18:08:30.120 に答える
1

わかった。したがって、これを完全にテストしていませんが、返信があれば、コメントするか、この提案を変更します. しかし、単純化されたテストケースで foo() のバージョンでコンパイルし、親クラスが使用する型に固有のものにするサンプルコードを次に示します。

template< typename T >
class TestClass
{
  typedef struct PlaceholderType {};

public:
  template< typename T2 >
  typename std::enable_if< !std::is_same<T2, PlaceholderType>::value && std::is_same<T, float>::value, void >::type MyFunc( T2 param ) { std::cout << "Float"; }

  template< typename T2 >
  typename std::enable_if< !std::is_same<T2, PlaceholderType>::value && !std::is_same<T, float>::value, void >::type MyFunc( T2 param ) { std::cout << "Non-float"; }
};


int main(int argc, char* argv[])
{
  TestClass<int> intClass; // should only have the MyFunc(int) version available
  TestClass<float> floatClass; // should only have the MyFunc(float) version available

  intClass.MyFunc(5); // should output "Non-float"
  intClass.MyFunc(5.0f); // should output "Non-float"
  floatClass.MyFunc(2.0f); // should output "Float"
  floatClass.MyFunc(2); // should output "Float"
}
于 2014-05-01T18:44:44.917 に答える