3

I have a code like:

#include <tuple>
#include <utility> 
#include <iostream>

template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> {};
template<int ...S> struct gens<0, S...> { typedef seq<S...> type; };

template<typename ValueType>
bool get_value(ValueType& value, int index) {
    //just for test
    value = 100;
    return true;
}


template<>
bool get_value(const char*& value, int index) {
    //just for test
    value = "Hello?";
    return true;
}

template<int index, std::size_t remaining, typename... Args>
struct arg_helper {
    inline static bool
    get_args(std::tuple<Args...>& t) {
        if (get_value(std::get<index>(t), index)) {
            return arg_helper<index + 1, remaining - 1, Args...>::get_args(t);
        }
        else {
            return false;
        }
        return true;
    }
};


template<std::size_t index, typename... Args>
struct arg_helper<index, 0, Args... > {
    inline static bool
    get_args(std::tuple<Args...>& t) {
        return true;
    }
};


template<typename R, typename... Args, int ...S>
void callFunc(R(func)(Args...), seq<S...>, std::tuple<Args...>& tup) {
    func(std::get<S>(tup) ...);
}

template<typename R, typename... Args>
void TestFunc(R(func)(Args...)) {
    std::tuple<Args...> tup;

    arg_helper<0, sizeof ...(Args), Args...>::get_args(tup);

    callFunc(func, typename gens<sizeof...(Args)>::type(), tup);
}

static void FuncA(int test, const char* str) {
    std::cout << "test func" << test << str << std::endl;
}


int main() {
    TestFunc(FuncA);
    return 0;
}

It can run on MSVC2013, but compiler error on GCC on the line :

arg_helper<0, sizeof ...(Args), Args...>::get_args(tup);

What am I doing wrong?

BTW: I know iterate over tuple it can run on gcc, but seems not work for MSVC2013

Community
  • 1
  • 1
ejkoy
  • 197
  • 1
  • 1
  • 8
  • What is the full error message you get? – NathanOliver Jul 21 '16 at 12:09
  • @NathanOliver http://coliru.stacked-crooked.com/a/e6e3be97c63bac4c can try here. – ejkoy Jul 21 '16 at 12:14
  • Slighty off-topic, but: make sure to [take care when using template specializations](http://www.gotw.ca/publications/mill17.htm), as these do not overload. Lets say you were to implement another template function which overloads `bool get_value(ValueType& value, int index)`, say `bool get_value(ValueType*& value, int index)`. For a call to `get_value` with a first argument of type `char*`, we would expect the specialization `bool get_value(const char*& value, int index)` to be chosen in the overload resolution, but depending on the order of occurence of the definition of the overloaded ... – dfrib Jul 21 '16 at 13:18
  • ... base template function (`bool get_value(const T*& ..., size_t ...)`), the seemingly more general generic function might be picked over the fully specialized one. The base template overload `bool get_value(const T*& ..., size_t ...)` is seen as the best match in the overload resolution, and only after this choice do the compiler look at possible template specifications _of the chosen base template function_. The moral here is that you might as well let the specialization be a good old non-template function (remove `template <>`). – dfrib Jul 21 '16 at 13:18

1 Answers1

3

It appears to be because you are mismatching int and size_t in your non-type template parameters. Change them all over to size_t and you're okay:

Demo (GCC)

Demo (Clang)

#include <tuple>
#include <utility> 
#include <iostream>

template<size_t ...> struct seq {};
template<size_t N, size_t ...S> struct gens : gens<N - 1, N - 1, S...> {};
template<size_t ...S> struct gens<0, S...> { typedef seq<S...> type; };

template<typename ValueType>
bool get_value(ValueType& value, size_t index) {
    //just for test
    value = 100;
    return true;
}


template<>
bool get_value(const char*& value, size_t index) {
    //just for test
    value = "Hello?";
    return true;
}

template<size_t index, std::size_t remaining, typename... Args>
struct arg_helper {
    static bool
    get_args(std::tuple<Args...>& t) {
        if (get_value(std::get<index>(t), index)) {
            return arg_helper<index + 1, remaining - 1, Args...>::get_args(t);
        }
        else {
            return false;
        }
        return true;
    }
};

template<std::size_t index, typename... Args>
struct arg_helper<index, 0, Args... > {
    static bool
    get_args(std::tuple<Args...>& t) {
        return true;
    }
};


template<typename R, typename... Args, size_t ...S>
void callFunc(R(func)(Args...), seq<S...>, std::tuple<Args...>& tup) {
    func(std::get<S>(tup) ...);
}

template<typename R, typename... Args>
void TestFunc(R(func)(Args...)) {
    std::tuple<Args...> tup;

    arg_helper<0, sizeof ...(Args), Args...>::get_args(tup);

    callFunc(func, typename gens<sizeof...(Args)>::type(), tup);
}

void FuncA(int test, const char* str) {
    std::cout << "test func" << test << str << std::endl;
}


int main() {
    TestFunc(FuncA);
    return 0;
}
AndyG
  • 39,700
  • 8
  • 109
  • 143
  • 1
    Possibly worth mentioning here as well: there's really no reason for letting (the fully specialized function) `get_value(const char*& value, size_t index)` be a template specialization: it might as well be non-template function. – dfrib Jul 21 '16 at 13:23