0

I can run this code, however when I enable the 3 out-commented lines it does not compile anymore and gives the following error:

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'

My idea why it isnt working is that the compiler wants to make sure Bla compiles for all sorts of template parameters, but first_argument can only handle template parameters that have the operator() defined. Does anybody know how to make this example work? I need it to select a class, here doStuff, based on whether the template parameters operator() accepts an argument or not, inside another templated class, here 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;
}

Thanks to all template nerds for helping :)

bodzcount
  • 95
  • 1
  • 8

1 Answers1

1

In your struct Bla you should say DoStuff<Type> doStuff; (typename is not needed or allowed here).

In (corrected version):

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

You were missing typename before first_argument<Functor>::type.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Ah thanks, yeah the one typename was just some stupid stuff i tried to make work after it did not work initially :P – bodzcount May 23 '16 at 18:36