如何检测方法是否是虚拟的?

Jar*_*d42 29 c++ virtual-functions sfinae type-traits c++11

我试图找出一个方法来查找方法是否是virtual:(https://ideone.com/9pfaCZ)

// Several structs which should fail depending if T::f is virtual or not.
template <typename T> struct Dvf : T { void f() final; };
template <typename T> struct Dvo : T { void f() override; };
template <typename T> struct Dnv : T { void f() = delete; };

template <typename U>
class has_virtual_f
{
private:
    template <std::size_t N> struct helper {};
    template <typename T>
    static std::uint8_t check(helper<sizeof(Dvf<T>)>*);
    template<typename T> static std::uint16_t check(...);
public:
    static
    constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t);
};
Run Code Online (Sandbox Code Playgroud)

测试用例:

struct V  { virtual void f(); };
struct NV {         void f(); };
struct E  {                   };
struct F  { virtual void f() final; }; // Bonus (unspecified expected output)

static_assert( has_virtual_f< V>::value, "");
static_assert(!has_virtual_f<NV>::value, "");
static_assert(!has_virtual_f< E>::value, "");
Run Code Online (Sandbox Code Playgroud)

但是我得到了error: 'void Dvf<T>::f() [with T = NV]' marked final, but is not virtual.
如果我不使用sizeof,直接Dvf<T>*check,我没有编译错误,但check不被丢弃在SFINAE"坏"类型:(.

检测方法是否正确的方法是virtual什么?

W.F*_*.F. 14

代码并不完美,但它基本上通过了测试(至少在7和7之后的wandbox和gcc上可用的clang中):

#include <type_traits>

template <class T>
using void_t = void;

template <class T, T v1, T v2, class = std::integral_constant<bool, true>>
struct can_be_compaired: std::false_type { };

template <class T, T v1, T v2>
struct can_be_compaired<T, v1, v2, std::integral_constant<bool, v1 == v2>>: std::true_type { };

template <class T, class = void>
struct has_virtual_f: std::false_type { };

template <class T>
struct has_virtual_f<T, void_t<decltype(&T::f)>>{
    constexpr static auto value = !can_be_compaired<decltype(&T::f), &T::f, &T::f>::value;
};

struct V  { virtual void f() { }      };
struct NV {         void f() { }      };
struct E  {                           };
struct F  { virtual void f() final{ } }; // Bonus (unspecified expected output)

int main() {
   static_assert( has_virtual_f< V>::value, "");
   static_assert(!has_virtual_f<NV>::value, "");
   static_assert(!has_virtual_f< E>::value, "");
   static_assert( has_virtual_f< F>::value, "");
}
Run Code Online (Sandbox Code Playgroud)

[现场演示]


相关标准件理论上让特质飞:[expr.eq] /4.3,[expr.const] /2.23

  • @dau_sama但是:`表达式e是一个核心常量表达式,除非按照抽象机的规则对e求值将对以下表达式之一求值:(...)关系或相等运算符,其结果未指定; (...)` (2认同)
  • @dau_sama,这意味着两个指针在指向虚方法时是否应该相等是未指定的,但是当在 constexpr 上下文中测试相等性时,它明确定义了编译器应该做什么 - 它不是核心常量表达式,因此它应该导致替换失败。 (2认同)

小智 13

可能无法确定特定方法是否存在virtual.我之所以这么说,是因为Boost项目研究了多年的特征,从未产生过这样的特质测试.

但是,在C++ 11中,或使用Boost库,您可以使用is_polymorphic<>模板测试类型以查看类型是否具有虚函数.请参阅std :: is_polymorphic <>boost :: is_polymorphic <>以供参考.