Help with ambiguity

Can someone resolve this ambiguity for me? The function 'test' is supposed to determine how many arguments a given function needs (from a given tuple).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <tuple>
#include <utility>

template <typename Tuple, std::size_t... Is, typename F, typename = decltype(std::declval<F>()(std::get<Is>(std::declval<Tuple>())...))>
void test_impl (const Tuple&, const std::index_sequence<Is...>&, F) {
	std::cout << sizeof...(Is) << " arguments needed.\n";
}

template <typename Tuple, std::size_t... Is, typename F>
void test_impl (const Tuple& tuple, const std::index_sequence<Is...>&, F f) {
//	std::cout << "More than " << sizeof...(Is) << " arguments needed.\n";
	test_impl (tuple, std::index_sequence<Is..., sizeof...(Is)>{}, f);
}

template <typename Tuple, typename F>
void test (const Tuple& tuple, F f) {
	test_impl(tuple, std::index_sequence<0>{}, f);
}

void foo (int, char, bool) {}

int main() {
        const auto tuple = std::make_tuple(5, 'a', true, 3.5);
	test (tuple, foo);
}


The output is supposed to be "3 arguments needed."

By the way, I know that

1
2
3
4
5
6
7
8
template <typename Function> struct ArgumentSize;

template <typename R, typename... Args>
struct ArgumentSize<R(Args...)> : std::integral_constant<std::size_t, sizeof...(Args)> {};

// ...

std::cout << ArgumentSize<decltype(foo)>::value;

will get the job done, but I want to know how to resolve the above ambiguity.
Last edited on
Maybe this'll help.
http://cppcodereviewers.com/more-generic-for_each_tuple/

I have to say, I don't quite understand what you're trying to do. I'd imagine you want to call some function on a tuple, and you're figuring out how to do the bind. The bit that throws me is, you have tuple "(5, 'a', true, 3.5)", and func void foo (int, char, bool) {}. So even if you got the binding right, it ought to complain about passing that tuple to that function.

Anyway, the example in the link explains the process. I'm not so keen on it myself, but there it is.
Here's one way I've found:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <tuple>
#include <utility>

struct Otherwise {  // ***
	Otherwise(...) {}  // Any value passed in the last argument of test_impl can be (implicitly) converted to an Otherwise object.
};

template <typename Tuple, std::size_t... Is, typename F, typename = decltype(std::declval<F>()(std::get<Is>(std::declval<Tuple>())...))>
void test_impl (const Tuple&, const std::index_sequence<Is...>&, F, int) {
	std::cout << sizeof...(Is) << " arguments needed.\n";
}

template <typename Tuple, std::size_t... Is, typename F>
void test_impl (const Tuple& tuple, const std::index_sequence<Is...>&, F f, Otherwise) {
//	std::cout << "More than " << sizeof...(Is) << " arguments needed.\n";
	test_impl (tuple, std::index_sequence<Is..., sizeof...(Is)>{}, f, 0);  // *** Pass an integer, e.g. 0.
}

template <typename Tuple, typename F>
void test (const Tuple& tuple, F f) {
	test_impl(tuple, std::index_sequence<0>{}, f, 0);
}

void foo (int, char, bool) {}

int main() {
    const auto tuple = std::make_tuple(5, 'a', true, 3.5);
	test (tuple, foo);  // 3 arguments needed.
}
Last edited on
Topic archived. No new replies allowed.