简体   繁体   English

模板类的模板化隶属函数

[英]Templated Member Function of Templated Class

I have a templated C++ class which has a templated member function as well. 我有一个模板化的C ++类,它也有一个模板化的成员函数。 The template parameters of this member function are dependent on the class's template parameters in a specific way (please see the code below). 此成员函数的模板参数以特定方式依赖于类的模板参数(请参阅下面的代码)。 I am instantiating (not specializing) this class for two different values of its template parameter. 我正在为这个类实例化(不专门化)它的模板参数的两个不同值。 Everything compiles till this point. 一切都汇编到这一点。 However, if I invoke the templated member function, the call for only the first instantiated object compiles and not the second one. 但是,如果我调用模板化成员函数,则只调用第一个实例化对象而不是第二个实例。 It appears as if the compiler is not instantiating the templated member function for the second instantiation of the template class. 看起来好像编译器没有为模板类的第二个实例化实例化模板化成员函数。 I am compiling the code below using "g++ filename.cpp" and am getting the following error: 我正在使用“g ++ filename.cpp”编译下面的代码,并收到以下错误:

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

This is the line calling b.init(&combination_2) 这是调用b.init(&combination_2)

g++ --version => g++ (Ubuntu/Linaro 4.4.7-1ubuntu2) 4.4.7 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 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;
}

It is not feasible to modify the classes corresponding to Base, Dependent or Combination from my example code in our actual project. 从我的实际项目中的示例代码修改与Base,Dependent或Combination对应的类是不可行的。 What I am really wondering is whether my syntax for defining Manager::init() is wrong, or whether there is some known property/feature/constraint of C++ or g++ that wouldn't allow this code? 我真正想知道的是我的定义Manager :: init()的语法是否错误,或者是否有一些C ++或g ++的已知属性/特性/约束不允许这些代码?

The code below compiles for me, I have simplified your code a little, though it still does the same thing. 下面的代码为我编译,我已经简化了你的代码,虽然它仍然做同样的事情。

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

EDIT : A 2nd solution so as to forbid the mixed use of combination in managers, as the OP has noticed in the comments below. 编辑 :第二种解决方案,以禁止在管理人员中混合使用组合,正如OP在下面的评论中所注意到的那样。 Now I'm using std::is_same to check the "concept" contract. 现在我使用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();
    }

};

If you combine inheritance and go away from constant template parameters, extend the Combination to provide info on its template arguments, you can get the code to compile taking into account that you don't want this to compile: 如果组合继承并远离常量模板参数,请扩展组合以提供有关其模板参数的信息,您可以获取要编译的代码,同时考虑到您不希望编译它:

b.init(&combination_1);

You are trying very hard to specify and fix the type of the Combination for the init member template within your Manager indirectly , even though the init template will deduce it since it is the only parameter of the function, and the type si defined within main anyway. 您正在努力间接地在Manager中为init成员模板指定和修复组合的类型,即使init模板将推断它,因为它是函数的唯一参数,并且主要在main中定义类型si 。

Would you consider templating the init directly with the Combination? 你会考虑直接用组合模板化init吗?

This way, everything apart from the init() declaration remains the same, and your code compiles as you wanted to initially: 这样,除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;
}

In this case, you can extend the Combination template to provide access to its template parameters to the client code. 在这种情况下,您可以扩展组合模板以提供对其客户端代码的模板参数的访问。 Of course the template C in this case becomes a refinement of the Combination concept as soon as you rely on its implementation within the init member function (accessing the stored template argument values, etc). 当然,只要您在init成员函数中依赖它的实现(访问存储的模板参数值等),模板C在这种情况下就会成为Combined概念的细化。

Your code is correct, except for the function calling part. 您的代码是正确的,除了函数调用部分。

a.init<PP, Combination>( &combination_1 );
b.init<XX, Combination> ( &combination_2 );

This compiles and runs peacefully. 这可以安静地编译和运行。

The only thing I see is 我唯一看到的是

template <typename DependentProperty<B>::Dependent D,
          template<Base, <-- wrong
                typename DependentProperty<B>::Dependent <-- wrong
          > class T>
void init(T<B, D>* t);

Your class Combination waits values as a template parameter, but you want to give him types 您的类Combination 作为模板参数等待,但您希望为其提供类型

I spent some time to fix it - like that 我花了一些时间来解决它 - 就像那样

template <typename DependentProperty<B>::Dependent D,
          template<Base BB,
                typename DependentProperty<BB>::Dependent DD
          > class T>
void init(T<B, D>* t);

and many other variants, but had no success. 和许多其他变种,但没有成功。

Excuse me for arrange it as an answer, but I couldn't type so many code in a comment 请原谅我作为答案安排它,但我无法在评论中输入这么多代码

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

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