我是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中问我第一个问题:-)
答案 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在一堂课中可能是最好的选择:
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;
}
}
};