【问题标题】:Template a virtual method from base class instead of use overloading从基类模板化虚拟方法而不是使用重载
【发布时间】:2015-12-22 10:05:27
【问题描述】:

我得到了奇怪的代码,必须扩展它。但我决定创建一个模板,而不是多次复制粘贴。但是被一块可怕的石头抓住了。

这是一个示例代码:

template<typename T>
class anyClass {};

template<typename T>
class Outer : public anyClass<T>
{
public:
   using value_t = T;
   class Inner
   {
      virtual void foo(value_t);
   };
};

class specializer : protected Outer::Inner
{
   virtual void foo(int) override {}
}

我必须扩展 virtual void foo(value_t) 的专精。

例子:

class specializer : protected Outer::Inner
{
   virtual void foo(int) override {}
   virtual void foo(float) override {}
   virtual void foo(string) override {}
   virtual void foo(bar) override {}
   // And so on...
 }

问题 1:尽管 class specializer : protected Outer::Inner 遗漏了一个参数,为什么这个例子有效?

所有的重载几乎都是一样的。我已经创建了这个函数。

template<typename anyType>
void meow( anyType )
{
/***/
}

我的问题在这里:

virtual void foo(anytype value) //<< replace anytype with what?
{
   meow<anytype>( value );
}

我需要 Outer::value_T 类型,但我不知道如何获取它。

问题 2:我如何通过调用foo 来使用meow

请随时询问更多信息。

更新

我再次查看原始代码并意识到,我忽略了一个重要的 using/typedef。 工作代码如下:

class specializer : protected Outer<int, float, string, bar>::Inner //Yes a variadic-template
{
   virtual void foo(int) override {}
   virtual void foo(float) override {}
   virtual void foo(string) override {}
   virtual void foo(bar) override {}
   // And so on...
 }

所以问题 1 解决了

【问题讨论】:

  • "class specializer : protected Outer::Inner" no such class Outer::Inner (第一个字母是大写的)
  • 另外,也没有Outer::inner这样的类,因为Outer是一个模板,而不是一个类。
  • @user3514538 谢谢,已解决。
  • @user2079303 我同意这一点。这就是我对示例代码编译并正常工作(原始形式)感到困惑的原因。
  • @Syrlia,它成功了!?在什么工具链上!? GCC 拒绝它,ideone.com/3RAEvF,这是理所当然的。

标签: c++ templates c++11 inner-classes virtual-functions


【解决方案1】:

为什么这个例子有效,虽然 class specializer : protected Outer::Inner 错过了一个参数?

示例does not work。它不起作用,因为Outer 不是一种类型。此外,即使inner 只有一个foo,您也会覆盖foo 的多个重载。还有几个语法错误。 如果它似乎可以工作,那么编译器正在做一些非标准的事情。

关于你的第二个问题:

virtual void foo(anytype value) //<< replace anytype with what?

您将其替换为您打算覆盖其重载的类型。例如,如果您打算覆盖foo(int),则将anytype 替换为int

问题 2:如何通过调用 foo 来使用 meow?

只需在foo 中调用meow

【讨论】:

  • 你是对的,谢谢。我在代码中检测到 typedef 后面的隐藏可变参数并更新了我的问题。
【解决方案2】:

您必须将specializer 设为模板类。

#include <iostream>

template<typename T> void meow(T x) 
{
    std::cout << x << std::endl;
}

template<typename T>
class anyClass {};

template<typename T>
class Outer : public anyClass<T>
{
public:
   using value_t = T;
   class Inner
   {
      virtual void foo(Outer<T>::value_t);
   };
};

template<typename T>
class specializer : protected Outer<T>::Inner
{
   virtual void foo(T x) override 
   {
       meow(x);
   }
};

我想知道这将如何帮助您更改 OuteranyClass 中的行为,因为您没有显示代码来显示实际使用 Inner 的位置和方式。没有它,它只是猜测。

我感觉您实际上想要实现的是向您传递一个函数(或策略?)Outer 类,在您的代码中由 Inner 表示。将其作为模板参数传递会更好。

template<typename T>
class anyClass {};

template<typename T, typename Inner = meow<T>>
class Outer : public anyClass<T>
{
public:
   using value_t = T;

   // somewhere in your code
   Inner i;
   i.meow( any_value );
};

您也可以将std::function 传递给构造函数。 模板 类 anyClass {};

template<typename T>
class Outer : public anyClass<T>
{
public:
   using value_t = T;

   Outer( std::function<void (value_t)> inner);

   // somewhere in your code
   i.meow( any_value );

   std::function<void (value_t)> i;
};

【讨论】:

  • 那行得通。但目前我无法更改类型,原因有很多。我试图解决这些原因。
【解决方案3】:

最初我简单化了一点。 这是我的问题的可编译示例:http://ideone.com/9U7J1a 我删除了所有不利的代码。我知道这个设计很糟糕,但我对它没有影响。

class bar {};
class string {};

template<typename _T>
class ModelContainer 
{
    public:
    using value_type = _T;

   class Delegate {
     public:
       virtual void foo( value_type value);
   }; 
};

template< typename... _Ts >
class ModelManager__AbstractBase : protected ModelContainer< _Ts >...
{
public:
  class Delegate : public ModelContainer< _Ts >::Delegate... {
  public:
    virtual ~Delegate( ) = default;
  };
};


using ModelManager__Base = ModelManager__AbstractBase<
    int,
    float,
    string,
    bar
>;

class ModelManager : public ModelManager__Base {
    /* Some functions */
};

class spezializer : ModelManager::Delegate
{
    public:
    virtual ~spezializer() = default;
        //Uncommend to see my error  
       // virtual void foo( value_type value) override // << value_type unknown
       // {/* Calling everytime the same method, no matter which value_type*/}
};

【讨论】:

  • 刚刚尝试使用代码并实例化了ModelManager::Delegate。它不编译。
  • 添加了缺少的public(见编辑)。现在,当我尝试使用 std::string s 调用 d.foo(s) 时,我收到一个编译器错误,即对 foo 的调用不明确。
  • 另外,这应该是问题的一部分。如果您提供最少但完整且实际编译的示例,则获得好答案的机会会高得多。就像现在一样,很多人不会尝试回答这个问题。
  • 您必须只实例化 spezializer 并与他一起工作。其余部分对于应用程序的其他部分是必需的。通过添加公共我可以实例化 spezializer。只剩下 Foo 方法了。
  • 不,下面的 sn-p 将无法编译:spezializer d; std::string s; d.foo(s); 有一个模棱两可的错误。
猜你喜欢
  • 2022-11-30
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 2020-10-21
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
相关资源
最近更新 更多