Специализация шаблона на основе аргументов функции члена шаблона параметра

62
5

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

1>d:\git\testprojekt\testprojekt\testprojekt.cpp(41): warning C4346: 'first_argument<F>::type': dependent name is not a type
1> d:\git\testprojekt\testprojekt\testprojekt.cpp(41): note: prefix with 'typename' to indicate a type
1> d:\git\testprojekt\testprojekt\testprojekt.cpp(43): note: see reference to class template instantiation 'Bla<Type>' being compiled
1>d:\git\testprojekt\testprojekt\testprojekt.cpp(41): error C2923: 'DoStuff': 'first_argument<F>::type' is not a valid template type argument for parameter 'Arg'
1> d:\git\testprojekt\testprojekt\testprojekt.cpp(22): note: see declaration of 'first_argument<F>::type'

Моя идея, почему он не работает, заключается в том, что компилятор хочет убедиться, что Bla компилируется для всех параметров шаблона, но first_argument может обрабатывать только параметры шаблона, которые имеют оператор(). Кто-нибудь знает, как заставить этот пример работать? Мне нужно это, чтобы выбрать класс, здесь doStuff, в зависимости от того, принимает ли параметр шаблона operator() аргумент или нет, внутри другого шаблонного класса, здесь Bla.

#include <iostream>

template<typename F, typename Ret>
void helper(Ret(F::*)());

template<typename F, typename Ret>
void helper(Ret(F::*)() const);

template<typename F, typename Ret, typename A, typename... Rest>
char helper(Ret(F::*)(A, Rest...));

template<typename F, typename Ret, typename A, typename... Rest>
char helper(Ret(F::*)(A, Rest...) const);

template<typename F>
struct first_argument {
typedef decltype(helper(&F::operator())) type;
};

template <typename Functor, typename Arg = first_argument<Functor>::type>
struct DoStuff;

template <typename Functor>
struct DoStuff<Functor, char>
{
void print() { std::cout << "has arg" << std::endl; };
};

template <typename Functor>
struct DoStuff<Functor, void>
{
void print() { std::cout << "does not have arg" << std::endl; };
};

template <typename Type>
struct Bla
{
//DoStuff<typename Type> doStuff;
//void print() { doStuff.print(); };
};

int main()
{
struct functorNoArg {
void operator() () {};
};

struct functorArg {
void operator()(int a) { std::cout << a; };
};

auto lambdaNoArg = []() {};
auto lambdaArg = [](int a) {};

std::cout << std::is_same<first_argument<functorArg>::type,int>::value <<std::endl; // this works

DoStuff<functorArg> doStuff;
doStuff.print();

DoStuff<functorNoArg> doStuff2;
doStuff2.print();

DoStuff<decltype(lambdaArg)> doStuff3;
doStuff3.print();

DoStuff<decltype(lambdaNoArg)> doStuff4;
doStuff4.print();

Bla<functorArg> bla;
//bla.print();

return 0;
}

Спасибо всем шаблонам за помощь :)

спросил(а) 2016-05-23T21:20:00+03:00 3 года, 10 месяцев назад
1
Решение
52

В вашей struct Bla вы должны сказать DoStuff<Type> doStuff; (typename не требуется или разрешено здесь).

В (исправленная версия):

template <typename Functor, typename Arg = typename first_argument<Functor>::type> struct DoStuff;

Вам не было имени typename перед first_argument<Functor>::type.

ответил(а) 2016-05-23T21:29:00+03:00 3 года, 10 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема