c++ 사용법 - 방법이 사실인지 알아내는 방법?




enable_if 17 (3)

메소드가 virtual 인지 찾기 위해 특성을 만들려고했습니다. ( https://ideone.com/9pfaCZ )

// Seveval 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);
};

테스트 케이스 :

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

하지만 error: 'void Dvf<T>::f() [with T = NV]' marked final, but is not virtualerror: 'void Dvf<T>::f() [with T = NV]' marked final, but is not virtual .
Dvf<T>* sizeofDvf<T>* 를 직접 사용하지 않으면 컴파일 오류가 발생하지 않지만 SFINAE에서 "bad"유형에 대해서는 check 가 삭제되지 않습니다.

방법이 virtual 인지를 탐지하는 적절한 방법은 무엇입니까?


Answers

특정 메소드가 virtual 인지 판별하는 f}은 아마도 없습니다. Boost 프로젝트 가 수년간 형질을 연구했기 때문에 결코 그런 특성 검사를 생산하지 않았기 때문에 나는 이것을 말한다.

그러나 C ++ 11 또는 Boost 라이브러리 를 사용하면 is_polymorphic<> 템플릿을 사용하여 유형을 테스트하여 유형에 가상 함수가 있는지 확인할 수 있습니다. 참조를 위해 std::is_polymorphic<> 또는 boost::is_polymorphic<> 을 참조하십시오.


코드는 완벽하지는 않지만 기본적으로 테스트를 통과합니다 (최소한 wandbox 및 gcc에서 사용할 수있는 모든 clang은 7이됩니다).

#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, "");
}

[라이브 데모]

이론적으로 특성이 적절하게 작동하도록하는 관련 표준 부품 : [expr.eq]/3.3 , [expr.const]/2.21


가상 생성자는 불가능하지만 가상 소멸자가 가능합니다. 실험 해 봅시다 ....

#include <iostream>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

위의 코드는 다음을 출력합니다.

Base Constructor Called
Derived constructor called
Base Destructor called

파생 된 객체의 생성은 구조 규칙을 따르지만 "b"포인터 (기본 포인터)를 삭제할 때 기본 소멸자 만 call이라는 것을 알았습니다.하지만 이런 일이 있어서는 안됩니다. 적절한 작업을 수행하려면 기본 소멸자를 가상으로 만들어야합니다. 이제 다음 사항을 확인하십시오.

#include <iostream>

using namespace std;

class Base
{ 
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    virtual ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

다음과 같이 출력이 변경되었습니다.

Base Constructor Called
Derived constructor called
Derived destructor called
Base Destructor called

따라서 기본 포인터 (파생 된 객체에 대한 할당을 취합니다!)는 파기 규칙, 즉 파생 된 파생 된 파열을 따릅니다. 반면에 생성자에는 가상 생성자와 같은 것이 없습니다.







c++ c++11 sfinae typetraits virtual-method