模板化类的模板化成员函数
Templated Member Function of Templated Class
我有一个模板化的C++类,它也有一个模板化的成员函数。此成员函数的模板参数以特定方式依赖于类的模板参数(请参阅下面的代码)。我正在实例化(而不是专门化)此类,用于其模板参数的两个不同值。一切都编译到这一点。但是,如果我调用模板化成员函数,则仅编译对第一个实例化对象的调用,而不会编译第二个对象的调用。看起来好像编译器没有为模板类的第二个实例化实例化模板化成员函数。我正在使用"g ++文件名.cpp"编译下面的代码,并收到以下错误:
文件名.cpp:63:错误:调用"管理器<(基)1u>::init(组合<(基)1u,(依赖2)0u>*)"没有匹配函数
这是呼叫b.init(&combination_2)
的线路
version => g++ (Ubuntu/Linaro 4.4.7-1ubuntu2) 4.4.7
uname -a => Linux 3.2.0-25-generic-pae #40-Ubuntu SMP i686 i686 i386 GNU/Linux
enum Base {
AA,
BB,
CC
};
enum Dependent1 {
PP,
QQ,
RR
};
enum Dependent2 {
XX,
YY,
ZZ
};
template<Base B>
struct DependentProperty {
};
template<>
struct DependentProperty<AA> {
typedef Dependent1 Dependent;
};
template<>
struct DependentProperty<BB> {
typedef Dependent2 Dependent;
};
template <Base B, typename DependentProperty<B>::Dependent D>
class Combination {
public:
void reset() {}
int o;
};
template <Base B>
class Manager {
public:
template <typename DependentProperty<B>::Dependent D,
template<Base,
typename DependentProperty<B>::Dependent> class T>
void init(T<B, D>* t);
};
template <Base B>
template <typename DependentProperty<B>::Dependent D,
template<Base,
typename DependentProperty<B>::Dependent> class T>
void Manager<B>::init(T<B, D>* t) {
t->reset();
}
int main(int argc, char** argv) {
Manager<AA> a;
Manager<BB> b;
Combination<AA, PP> combination_1;
Combination<BB, XX> combination_2;
a.init(&combination_1);
b.init(&combination_2);
return 0;
}
在我们的实际项目中,从我的示例代码中修改与基本、依赖或组合相对应的类是不可行的。我真正想知道的是我定义 Manager::init() 的语法是否错误,或者是否有一些已知的 C++ 或 g++ 属性/功能/约束不允许此代码?
代码为我编译,我已经简化了你的代码,尽管它仍然做同样的事情。
template <Base B>
class Manager {
public:
typedef typename DependentProperty<B>::Dependent D; // if ever you need it
template <typename TCombinaison>
void init(TCombinaison* t)
{
t->reset();
}
};
int main(int argc, char** argv)
{
typedef Combination<AA, PP> CombinaisonA;
typedef Combination<BB, XX> CombinaisonB;
typedef DependentProperty<AA> DependencyPropertyA;
typedef DependentProperty<BB> DependencyPropertyB;
CombinaisonA combination_1;
CombinaisonB combination_2;
Manager<AA> a;
Manager<BB> b;
a.init(&combination_1);
b.init<&combination_2);
return 0;
}
编辑:第二种解决方案,以禁止在管理器中混合使用组合,正如OP在下面的评论中注意到的那样。现在我正在使用 std::is_same 来检查"概念"合约。
template <Base B, typename DependentProperty<B>::Dependent D>
class Combination {
public:
typedef typename DependentProperty<B>::Dependent DependencyType;
void reset() {}
int o;
};
template <Base B>
class Manager {
public:
typedef typename DependentProperty<B>::Dependent DependencyType;
template <typename TCombinaison>
void init(TCombinaison* t)
{
static_assert(std::is_same<TCombinaison::DependencyType, Manager::DependencyType>);
t->reset();
}
};
如果组合继承并远离常量模板参数,请扩展组合以提供有关其模板参数的信息,则可以获取要编译的代码,同时考虑到您不希望编译它:
b.init(&combination_1);
您正在努力间接地在管理器中指定和修复 init 成员模板的组合类型,即使 init 模板会推断它,因为它是函数的唯一参数,并且无论如何都是在 main 中定义的类型 si。
你会考虑直接使用组合来模板化初始化吗?
这样,除了 init() 声明之外的所有内容都保持不变,并且您的代码可以按照您最初想要的方式进行编译:
class Base
{
};
class AA
:
public Base
{
};
class BB
:
public Base
{
};
class Dependent1
{
};
class PP
:
public Dependent1
{};
class Dependent2
{};
class XX
:
public Dependent2
{};
template<class Base>
struct DependentProperty {
};
template<>
struct DependentProperty<AA> {
typedef Dependent1 Dependent;
};
template<>
struct DependentProperty<BB> {
typedef Dependent2 Dependent;
};
template <class Base>
class Combination {
public:
typedef Base CombinationBase;
typedef typename DependentProperty<Base>::Dependent CombinationDependent;
void reset()
{
}
int o;
};
template <class Base>
class Manager
{
public:
// Any type C
template<class C>
void init (C* t)
{
// Any type C conforming to the implicit interface holding reset()
t->reset();
// Forcing specific combination
Base b = typename C::CombinationBase();
// Forcing it again
typename DependentProperty<Base>::Dependent d = typename C::CombinationDependent();
}
};
int main(int argc, char** argv) {
Combination<AA> combination_1;
Manager<AA> a;
a.init(&combination_1);
Manager<BB> b;
Combination<BB> combination_2;
b.init(&combination_2);
b.init(&combination_1);
return 0;
}
在这种情况下,可以扩展组合模板,以提供对客户端代码的模板参数的访问。当然,在这种情况下,只要您依赖它在 init 成员函数中的实现(访问存储的模板参数值等),模板 C 就会成为组合概念的改进。
你的代码是正确的,除了函数调用部分。
a.init<PP, Combination>( &combination_1 );
b.init<XX, Combination> ( &combination_2 );
这将和平地编译和运行。
我唯一看到的是
template <typename DependentProperty<B>::Dependent D,
template<Base, <-- wrong
typename DependentProperty<B>::Dependent <-- wrong
> class T>
void init(T<B, D>* t);
您的类Combination
等待值作为模板参数,但您希望为他提供类型
我花了一些时间来修复它 - 就像那样
template <typename DependentProperty<B>::Dependent D,
template<Base BB,
typename DependentProperty<BB>::Dependent DD
> class T>
void init(T<B, D>* t);
和许多其他变体,但没有成功。
请原谅我将其安排为答案,但我无法在评论中键入这么多代码
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针