Неопределенность шаблона VС++ 14 между указателем на элемент и указателем на функцию-член

У меня проблема с шаблонами функций с помощью компилятора vs14. Таким образом, следующий код демонстрирует проблему.

#include <iostream>
using namespace std;

class Class {
public:
    int memberFoo() {
        return 0;
    }
};

template <class VariableT, class C>
void nothing(const VariableT C::*memberV) {
    cout << "Pointer to member variable";
}

template <class R, class C>
void nothing(R (C::*memberF)()) {
    cout << "Pointer to member function";
}

int main() {

    nothing(&Class::memberFoo);

    return 0;
}

Компилятор позволяет мне знать, что функция nothing неоднозначна. Когда я вижу результат, у него, похоже, другое поведение, чем я ожидал. В первой функции nothing компилятор выводит VariableT как int(void). На самом деле это не так странно, но я полагал, что второй будет более подходящим и будет соответствовать. Что более интересно, если вы удалите const в первой перегруженной функции, программа будет скомпилирована правильно. Можете ли вы предложить мне, как с этим справиться, пожалуйста?

Ответы

Ответ 1

Вы можете исправить это, используя несколько удобных типов_таблиц, is_member_function_pointer и is_member_object_pointer:

template <class R, class C>
void nothing(R (C::*memberF)())
{
    std::cout << "Pointer to function" << std::endl;
}

template <class VariableT, class C>
auto nothing(const VariableT C::* memberV)-> typename std::enable_if<std::is_member_object_pointer<decltype(memberV)>::value>::type
{
    cout << "Pointer to member variable";
}

Live Demo

Тип по умолчанию из std::enable_if - void, поэтому возвращаемый тип остается void.

С вашего поста это звучит так, как должен быть создан шаблон функции-члена, но Visual Studio и Clang оба кричат ​​о двусмысленности, что, я полагаю, справедливо, учитывая Type Class::*, вы могли бы вывести указатель на элемент или указатель на функцию-член, предполагая, что подстановка ReturnType() действительна для Type (это то, что мы видим).

Итак, я решил пропустить все это и воспользоваться типом возвращаемого возврата, чтобы напрямую опросить параметр.


ИЗМЕНИТЬ

Включая текст link в T.C. комментарии

Раздел: 14.8.2.1 [temp.deduct.call]
Неясно, правильно ли сформировано следующее:

void foo(){}

template<class T>
void deduce(const T*) { }

int main() {
  deduce(foo);
}

Реализации различаются в их трактовке этого примера.

Действительно, вы заметили, что удаление const также устранило неоднозначность.