【问题标题】:Can't override virtual function using SFINAE (std::enable_if)无法使用 SFINAE (std::enable_if) 覆盖虚函数
【发布时间】:2017-03-29 22:35:28
【问题描述】:

下面的代码用B::foo() override 覆盖virtual A::foo()。如果 BROKEN 没有定义,那么它编译得很好。我对std::enable<std::is_pod<Q>::value>::type 恶作剧的理解是它有效地将SFINAE 表达式替换为void,这应该与普通的旧void 相同。

但是,它不会编译。我得到编译器错误:

英特尔编译器(icpc):

$ make a CXXFLAGS="-std=c++11 -DBROKEN"
icpc -std=c++11 -DBROKEN    a.cpp   -o a
a.cpp(24): error: object of abstract class type "B<int>" is not allowed:
            pure virtual function "A::foo" has no overrider
     B<int> b;
            ^

gcc:

$ make a CXXFLAGS="-std=c++11 -DBROKEN" CXX=g++
g++ -std=c++11 -DBROKEN    a.cpp   -o a
a.cpp: In function ‘int main()’:
a.cpp:24:11: error: cannot declare variable ‘b’ to be of abstract type ‘B<int>’
    B<int> b;
           ^
a.cpp:9:7: note:   because the following virtual functions are pure within ‘B<int>’:
 class B : A
       ^
a.cpp:5:16: note:       virtual void A::foo()
   virtual void foo() = 0;
                ^
make: *** [a] Error 1

这是测试用例:

#include <type_traits>

class A {
  public:
  virtual void foo() = 0;
};

template<typename T>
class B : A
{
  public:

#ifdef BROKEN
  template<class Q = T>
  typename std::enable_if<true>::type
#else
  void
#endif
  foo() override { }
};

int main()
{
   B<int> b;
   b.foo();
   return 0;
}

如果我不使用虚函数,std::enable&lt;true&gt; 会按预期工作。

附录

这些结果适用于 gcc 4.8.3。使用 gcc 5.3,我得到一行额外的编译器错误:

a.cpp:19:9: error: member template ‘std::enable_if<true>::type B<T>::foo()’ may not have virt-specifiers
   foo() override { }

     ^

为什么不呢?

【问题讨论】:

    标签: c++11 virtual sfinae


    【解决方案1】:

    这并不漂亮,但它完成了工作......使用 SFINAE 条件编译进行虚拟覆盖。它有更多的调用开销(foo() 调用 foo_x()),但也许编译器会优化它。

    #include <type_traits>
    
    class A {
      public:
      virtual void foo() = 0;
    };
    
    template<typename T>
    class B : A
    {
      public:
    
      template<class Q = T>
      typename std::enable_if<true>::type
      foo_x() { }
    
      void foo() override { foo_x(); }
    };
    
    int main()
    {
       B<int> b;
       b.foo(); // not an example of polymorphism! just want it to compile.
       return 0;
    }
    

    那个例子只是为了证明它可以编译并且没有用。 foo_x 的实际实现会有多个实现:

      template<class Q = T>
      typename std::enable_if<is_pod<Q>::value>::type
      foo_x() { /* do something with POD */}
    
      template<class Q = T>
      typename std::enable_if<std::is_base_of<std::string,Q>::value>::type
      foo_x() { /* do something with a std::string */}
    
      template<class Q = T>
      typename std::enable_if<std::is_base_of<MyCrazyClass,Q>::value>::type
      foo_x() { /* do something with a derived class of MyCrazyClass */}
    

    【讨论】:

    • 忘记我之前的评论,我错过了这一点。只是为了让其他读者清楚,您将有多个 foo_x 方法,每个方法都有 enable_if,因此对于每个 T,将启用一个,对吧?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多