Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent C++ guessing a second template argument?

I'm using a C++ library (strf) which, somewhere within it, has the following code:

namespace strf { template <typename ForwardIt> inline auto range(ForwardIt begin, ForwardIt end) { /* ... */ }  template <typename Range, typename CharT> inline auto range(const Range& range, const CharT* sep) { /* ... */ } } 

Now, I want to use strf::range<const char*>(some_char_ptr, some_char_ptr + some_length) in my code. But if I do so, I get the following error (with CUDA 10.1's NVCC):

error: more than one instance of overloaded function "strf::range" matches the argument list:             function template "auto strf::range(ForwardIt, ForwardIt)"             function template "auto strf::range(const Range &, const CharT *)"             argument types are: (util::constexpr_string::const_iterator, util::constexpr_string::const_iterator) 

The library code can probably be changed to avoid this (e.g. using:

inline auto range(const typename std::enable_if<not std::is_pointer<typename std::remove_cv<Range>::type>::value, Range &>::type range, const CharT* sep) 

to ensure Range is not a pointer); but I can't make that change right now. Instead, I want to somehow indicate to the compiler that I really really mean to only have one template argument, not one specified and another one deduced.

Can I do that?

Would appreciate answers for C++11 and C++14; C++17 answers involving deduction guides are less relevant but if you have one, please post it (for future NVCC versions...)


Update: The strf library itself has been updated to circumvent this situation, but the question stands as asked.

like image 773
einpoklum Avatar asked Dec 30 '19 23:12

einpoklum


People also ask

What is template argument deduction?

Template argument deduction is used when selecting user-defined conversion function template arguments. A is the type that is required as the result of the conversion. P is the return type of the conversion function template.

What is a template argument C++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

How many template arguments are there?

1) A template template parameter with an optional name. 2) A template template parameter with an optional name and a default. 3) A template template parameter pack with an optional name.


1 Answers

template<typename T> inline constexpr auto range1_ptr = strf::range<T>;  template<typename T> inline decltype(auto) range1(T begin, T end) {     return range1_ptr<T>(begin, end); } 

Then call range1 instead of strf::range.

range1_ptr<T>(...) can always be used to explicitly call the template taking one template argument, but does not do any deduction from the arguments. range1 replicates the deduction from the original strf::range template.

This works, because [temp.deduct.funcaddr]/1 says that template argument deduction when taking the address of a function without target type of the conversion is done on each candidate function template as if the parameter and argument lists of a hypothetical call were empty. So the second template argument cannot be deduced for the second overload with two template parameters. The only candidate left is the first overload, which will be chosen as the target of the function pointer.

As long as there is no second candidate function template for which a valid template-id with only one argument can be formed, range1_ptr can always be used to call the function template taking one argument unambiguously. Otherwise, the instantiation of range1_ptr will give an error because of ambiguity.

like image 138
walnut Avatar answered Sep 23 '22 11:09

walnut