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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With