基于类型

时间:2015-12-26 11:37:03

标签: c++ templates

我是C ++新手,特别是在处理模板时。我有一个模板类“Foo”,旨在采用不同的结构作为模板参数。我还需要一个类的成员函数,它根据类型模板参数的不同而有效,所以我专门研究这样一个函数。总体情况如下:

struct A
{

    float paramOfA;

};

struct B
{

    float paramOfB; 

};


template <typename T> 
class Foo
{
    public:
        void doSomethingOnType(T& arg);

    //...more functions and stuff...

};

// function specialisation for A's
template<> void Foo<A>::doSomethingOnType(A& a){

    //do something on member of A
    a.paramOfA = ...;

    std::cout<< "I've done something on a's member..."<<std::endl;


}

// function specialisation for B's
template<> void Foo<B>::doSomethingOnType(B& b){
    //do something on member of B
    b.paramOfB = ...;

    std::cout<< "I've done something on b's member..."<<std::endl;

}

到目前为止这么好,对吗?想象一下,现在我有一个源自B的结构C:

struct C:B
{

    float paramOfC;

};

现在,当我实例化一个采用C结构模板类型的Foo对象时,我希望函数“doSomethingOnType”在C的成员上保持B类型的函数的相同行为,这些行为来自B(paramOfB),尽管我没有为C结构类型专门设置这样的函数。例如

Foo<C> o;
C oneC;

o.doSomethingOnType(oneC);

我确信在执行上面的代码时,该函数将采用模板化类中给出的任何实现,而不是B的专用版本。但我真的想在使用C时保留函数的后一个实现类型,因为,从C派生出C,它对我来说很有意义,也节省了我为C的函数专门化编写更多代码行的时间,它具有与B相同的行为(想象一下B有50个成员而不是一个成员)。如上所述,是否有可能没有专门针对C结构类型的函数?

非常感谢您的帮助!

真的很高兴在stackoverflow中问我第一个问题:-)

2 个答案:

答案 0 :(得分:0)

虽然How do you force a templatization to match a base class?是一个优雅的解决方案,如果你的函数将T的一个实例作为参数,我想介绍几种方法,如果不是:

测试用例

class A1 {};
class A2:public A1 {};

class B{};
class C{};

包裹功能

这可能是最简单的解决方案:

template<typename T>
class Bar
{
        public:
        void fun()
        {
                fun_impl((T*)(0));
        }
        void fun_impl( A1* const)
        {
                cout << "A1" << endl;
        }
        void fun_impl(B* const)
        {
                cout << "B" << endl;
        }
        void fun_impl(void*)
        {
                cout << "Neither A nor B" << endl;
        }
};

Bar<A2>().fun(); // A1
Bar<B>().fun();  // B
Bar<C>().fun();  // Neither A nor B

因为fun_impl的优先级完全匹配(或作为可访问的基类)类型&gt;那些需要void*转换的版本,将启用正确的版本。 (注意:在clang3.7和gcc5.3上都是如此,但我没有提到标准)

但是,如果我们有class A3: private A1,则在编译Bar<A3>().fun()期间会出现错误。

以下两个解决方案需要C ++ 11:

类模板的部分专业化

template<typename T, bool  = std::is_base_of<A1, T>::value,

bool = std :: is_base_of :: value&gt;     struct Foo     {             void fun();     }; //主要版本

template<typename T>
struct Foo<T,false,false>
{
        void fun();
};  //Specialization of Neither A nor B

template<typename T>
void Foo<T,false,false>::fun()
{
        cout << "neither A nor B" << endl;
}

template<typename T>
struct Foo<T,true,false>
{
        void fun();
};  //Specialization of A

template<typename T>
void Foo<T,true,false>::fun()
{
        cout << "A" << endl;
}

template<typename T>
struct Foo<T, false, true>
{
        void fun();
};  //Specialization of B

template<typename T>
void Foo<T,false,true>::fun()
{
        cout << "B" << endl;
}

    Foo<A2>().fun();  //A
    Foo<B>().fun();   //B
    Foo<C>().fun();   //Neither A nor B
    Foo<APrivate>().fun();    //A

SFINAE

如果你不想专攻全班,也许SFINAE在一堂课中可能是最好的选择:

namespace
{
        class Helper1 {};
        class Helper2 {};
} // Helper classes to avoid ambiguity

template<typename T>
class Foo
{
        public:

        template<typename TIn= T, typename U= typename std::enable_if<std::is_base_of<A1, TIn>::value>::type >
                void fun(Helper1 = Helper1())
                {
                        cout << "A" << endl;
                }
        template<typename TIn=T ,typename U = typename std::enable_if<std::is_base_of<B, TIn>::value>::type >
                void fun(Helper2 = Helper2())
                {
                        cout << "B" << endl;
                }
        template<typename TIn = T, typename = typename std::enable_if<!std::is_base_of<A1,TIn>::value>::type ,
                typename = typename std::enable_if<!std::is_base_of<B,TIn>::value>::type >
                void fun()
                {
                        cout << "Neither A nor B" << endl;
                }
};

在上面的情况下,只有当函数匹配某些特定条件时才会实例化它。由于一个类中不允许三个void fun(),因此需要辅助类。

答案 1 :(得分:0)

你可以在一般模板功能中做一些钩子,虽然我讨厌它.... 这些代码可以如下:

template <typename T>
class Foo {
public:
  void doSomethingOnType(T& arg)
  {
    if (dynamic_cast<B*>(&arg) != NULL) {
      Foo<B> fb;
      fb.doSomethingOnType(arg);
    } else {
      std::cout << "I've done something on Foo's member..." << std::endl;
    }
  }

};