繁体   English   中英

模板类的模板化隶属函数

[英]Templated Member Function of Templated Class

我有一个模板化的C ++类,它也有一个模板化的成员函数。 此成员函数的模板参数以特定方式依赖于类的模板参数(请参阅下面的代码)。 我正在为这个类实例化(不专门化)它的模板参数的两个不同值。 一切都汇编到这一点。 但是,如果我调用模板化成员函数,则只调用第一个实例化对象而不是第二个实例。 看起来好像编译器没有为模板类的第二个实例化实例化模板化成员函数。 我正在使用“g ++ filename.cpp”编译下面的代码,并收到以下错误:

filename.cpp:63:错误:没有用于调用'Manager <(Base)1u> :: init(组合<(Base)1u,(Dependent2)0u> *)'的匹配函数

这是调用b.init(&combination_2)

g ++ --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;
}

从我的实际项目中的示例代码修改与Base,Dependent或Combination对应的类是不可行的。 我真正想知道的是我的定义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);

您正在努力间接地在Manager中为init成员模板指定和修复组合的类型,即使init模板将推断它,因为它是函数的唯一参数,并且主要在main中定义类型si 。

你会考虑直接用组合模板化init吗?

这样,除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在这种情况下就会成为Combined概念的细化。

您的代码是正确的,除了函数调用部分。

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);

和许多其他变种,但没有成功。

请原谅我作为答案安排它,但我无法在评论中输入这么多代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM