【发布时间】:2023-03-12 18:16:01
【问题描述】:
我有一个从FooDerived<T> 派生的模板类Foo<T>,它又是模板类Bar<T> 的模板参数,即我最终得到类似Bar< FooDerived<T> > 的东西。
template <typename T>
class Foo
{
public:
typedef T type_t;
virtual double compute() { return 1.0; }
};
template <typename T>
class FooDerived : public Foo<T>
{
public:
double compute() { return 42.0; }
};
template <typename T>
class Bar : public T
{
public:
void f()
{
// This function could vary depending on U (and possibly T)
std::cout << "Bar< T<U> > : " << this->compute() << std::endl;
}
};
我正在尝试根据FooDerived 的模板参数专门化Bar。例如,Bar< FooDerived<int> > 和 Bar< FooDerived<float> > 将具有不同的行为。
int main(void)
{
Bar< FooDerived<int> > a;
a.f();
Bar< FooDerived<float> > b;
b.f();
}
如何在 C++03(或 C++11)中有效地实现这一点?高效,我的意思是我想避免无用的代码重复(实际程序涉及的类型和函数比本示例中的要多得多)。此外,使用代码的人应该能够在不需要修改代码的情况下添加他们的专业化,因此任何类型的switch-like 解决方案都不会被采用。
我一直在研究涉及boost::mpl 的类似 SFINAE 的解决方案,例如boost::mpl::if_ 和 boost::is_same 来检查类型,但似乎没有什么能达到我的目标。我想这可能不适用于那种模板专业化。我总是以error: redefinition of 'Bar' 结尾,因为编译器似乎并不认为它是一种专业化,例如,如果我尝试做这样的事情:
模板 类 Bar : public T, private boost::mpl::if_, int, boost::mpl::false_>
使用boost::mpl::if_,无论是作为私有继承还是作为额外的模板参数,似乎都无法实现特化。
那么实现这样的事情的正确方法是什么?
更新 1
专门化所有案例是可能的,但隐藏在这个例子背后的真正问题实际上要复杂得多。我有一个CachedFunction<T> : public T,其中T 派生自Function<U>(函数、可微函数、二次可微函数等),其中U 是一种存储类型(密集或稀疏矩阵)。 CachedFunction 包含大量函数,其实现取决于存储类型和函数类型。因此,元编程似乎是避免某些代码重复的好方法。
更新 2
针对所提供的答案:我试图避免对所有涉及的案例进行这些明确的模板专业化。试想一下,Foo 派生的类有 3 或 4 个,Foo 有 2 或 3 种类型,Bar 包含 6 或 7 个函数,需要根据 @ 的类型进行不同处理987654346@ 和考虑的派生类。基本上,对于每个i、j 和k,我都需要实现:
template<> void Bar<FooDerived_i<Type_j> >::f_k(){ ... }
因此,我正在尝试看看是否还有其他“更清洁”的方式。
更新 3
如果我使用boost::is_same,我可以做这样的事情,但是这个解决方案使得在不修改代码的情况下处理新类型变得更加困难。
这是example:
#include <iostream>
#include <boost/type_traits/is_same.hpp>
typedef int type1;
typedef float type2;
template <typename T>
class Foo
{
public:
typedef T type_t;
virtual double compute() { return 1.0; }
};
template <typename T>
class FooDerived
{
public:
typedef T type_t;
double compute() { return 42.0; }
};
template <class T>
class Bar : public T
{
public:
void f()
{
// types have to be known...
if (boost::is_same<typename T::type_t, type1>::value)
std::cout << "Bar< T<type1> > : " << this->compute() << std::endl;
else if (boost::is_same<typename T::type_t, type2>::value)
std::cout << "Bar< T<type2> > : " << this->compute() << std::endl;
}
};
int main(void)
{
Bar< Foo<type1> > a;
a.f();
Bar< FooDerived<type2> > b;
b.f();
}
【问题讨论】:
-
您能否将尝试专门化
Bar的代码连同来自编译器的错误消息一起显示? -
@arne:当然,尽管这显然是完全错误的。我会在一分钟内更新问题。
-
你为什么不能只使用普通的专业化(没有任何 SFINAE 技巧)? IE。你定义了一个
template <> class Bar<FooDerived<int>>和一个template <> class Bar<FooDerived<float>>? -
@jogojapan:因为问题实际上有点复杂。从
Foo派生的每个类都可能对函数有不同的实现,因此这意味着要为大量情况编写专门化(number of types like int/float * number of functions like name() * number of derived classes),从而重复大量代码。如果可能的话,我想避免这种情况。这就是为什么我认为元编程可能是答案。我将编辑问题以添加此信息。 -
我明白了。所以你希望专业化只影响选定的成员函数,对吗?还有任何数据成员(或其类型)吗?
标签: c++ templates boost sfinae specialization