std :: is_member_function_pointer не компилируется, если false - PullRequest
10 голосов
/ 14 марта 2019

Что я ищу: У меня есть шаблонный класс, и я хочу вызвать функцию, если у класса есть требуемая функция, что-то вроде:

template<class T> do_something() {
    if constexpr (std::is_member_function_pointer<decltype(&T::x)>::value) {
        this->_t->x(); // _t is type of T*
    }
}

Что происходит: Компилятор не компилируется, если T не возвращает функцию. Маленький пример:

#include <type_traits>
#include <iostream>

class Foo {
public:
    void x() { }
};

class Bar { };

int main() {
    std::cout << "Foo = " << std::is_member_function_pointer<decltype(&Foo::x)>::value << std::endl;
    std::cout << "Bar = " << std::is_member_function_pointer<decltype(&Bar::x)>::value << std::endl;
    return 0;
}

Компилятор говорит:

is_member_function_pointer.cpp:17:69: error: no member named 'x' in 'Bar'; did you mean 'Foo::x'?
    std::cout << "Bar = " << std::is_member_function_pointer<decltype(&Bar::x)>::value << std::endl;

Итак, для чего нужен std::is_member_function_pointer, когда я не могу использовать его в if constexpr? Если я просто использую this->_t->x(), то компилятор тоже не сможет.

1 Ответ

17 голосов
/ 14 марта 2019

is_member_function_pointer не обнаруживает существование объекта T::x, он предполагает, что это делает, и возвращает, является ли он указателем на функцию-член.

Если вы хотите определить, существует он или нет, вы можете использовать идиому обнаружения .Пример:

#include <experimental/type_traits>

template<class T>
using has_x = decltype(&T::x);

template<class T> void do_something(T t) {
    if constexpr (std::experimental::is_detected<has_x, T>::value) {
        t.x(); 
    }
}

struct Foo {
    void x() { }
};

struct Bar { };

int main() {
    do_something(Foo{});
    do_something(Bar{});
}

живой пример на godbolt.org


Я написал статью об общей проблеме проверкидопустимость выражения в различных версиях C ++ Standard:

"проверка правильности выражения на месте с C ++ 17"

...