C ++为特定模板特化添加重载方法

时间:2014-05-01 17:24:45

标签: c++ templates overloading template-specialization name-hiding

我有一个非常有趣的问题:我有两个模板类。一个可以采用任何模板参数,另一个更专业(对于这个玩具问题,我们说它必须采取浮点)。

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

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

现在我有另一个模板类Foo。 Foo对它的模板参数没有限制,并且函数foo采用相同类型的CanBeAnythingMustBeFloat。我希望在这里使用显式模板实例化,所以当模板参数是浮点时,我只希望存在MustBeFloat重载。

最简单的解决方案似乎是专注于Foo,但我不喜欢在两个类之间复制接口的想法。我提出了一个几乎正常工作的CRTP解决方案,我将在一分钟内提到一个问题

/* 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> & )的调用隐藏在子类中,编译器给我&#34;没有匹配方法foo&#34;错误。如果我添加行using Parent::foo;以使其失效,我得到&#34; foo在父类中不存在&#34;实例化非浮点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> &);

一切正常。好极了!感谢那些帮助我找到解决方案的人,并提出了其他更具创造性的解决方案。

2 个答案:

答案 0 :(得分: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将是MustBeFloat<T>的typedef。否则,它将是Foo的私有成员类,因此foo()的调用者不可能合成该类型的左值。

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