Why can't I manually provide the template arguments?

為{幸葍}努か 提交于 2020-01-04 01:58:08

问题


I have a variadic template function f. This compiles fine (using g++ -std=c++11 and possibly using c++0x):

#include <tuple>

template<int ...>
struct seq { };

template <typename ...T, int ...S>
void f(std::tuple<T...> arg, seq<S...> s) {
  // ... do stuff
}

int main() {
  f<int>(std::tuple<int>(10), seq<0>());
  return 0;
}

The compiler automatically fills in the int ...S that works.

However, I can't seem to manually provide the integer arguments:

int main() {
  f<int, 0>(std::tuple<int>(10), seq<0>());
  return 0;
}

Output:

/tmp/t.cpp: In function ‘int main()’: /tmp/t.cpp:12:42: error: no
matching function for call to ‘f(std::tuple, seq<0>)’
/tmp/t.cpp:12:42: note: candidate is: /tmp/t.cpp:7:6: note:
template void f(std::tuple<_TElements ...>,
seq) /tmp/t.cpp:7:6: note: template argument
deduction/substitution failed:

I believe I've read that technically there should only be one variadic template parameter pack provided to a template function (and in the first case, it is completely determined by context), so that explains it(?).

For debugging, is there a way in GCC to output the expansion used for ...S to stderr or stdout? It would be very useful for debugging things like this when they don't compile at first.


回答1:


I know no way to specify two template argument packs manually. Since a template pack may contain arbitrarily many arguments, there is no way for the compiler to know when you meant the first one to stop and the second one to start. Automatic or partially automatic deduction seems to work, though, but I am not sure if this is just some generousity of g++...

I am not sure what you are actually trying to do, but I bet that you do not need both template packs at the same time. You might introduce one layer of indirection, e.g.,

template <typename ... Tuple_Elements>
void do_something_with_single_value(std::tuple<Tuple_Elements...> arg, int s) {
  // ... do stuff 
}

template <typename Tuple_Type, int ...S>
void f(Tuple_Type arg, seq<S...> s) {
  // ... do stuff which needs all S at the same time
  // ... call do_something_with_single_value in compile time loop to access tuple elements
}

Perhaps your signature is a hint that your function has too many responsibilities. Try to create smaller functions with clear responsibilities.

There is a way to output the arguments deduced for T and S, but only if the compiler can determine a match. For this, you would need to provoke an error at compile time:

template <typename ...T, int ...S>
void f(std::tuple<T...> arg, seq<S...> s) {
static_assert(std::tuple_size<std::tuple<T...>>::value < 0, "Provoked error message");
    // ... do stuff
}

This would generate the following output in your working example:

stack.cpp: In function ‘void f(std::tuple<_Elements ...>, seq<S ...>) [with T = {int}, int ...S = {0}]’:
stack.cpp:15:34:   instantiated from here
stack.cpp:10:2: error: static assertion failed: "Provoked error message"


来源:https://stackoverflow.com/questions/10824811/why-cant-i-manually-provide-the-template-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!