如何防止 C++ 猜测第二个模板参数?

ein*_*ica 27 c++ nvcc overload-resolution c++11 template-argument-deduction

我正在使用 C++ 库 ( strf ),其中的某处具有以下代码:

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) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想strf::range<const char*>(some_char_ptr, some_char_ptr + some_length)在我的代码中使用。但是如果我这样做,我会收到以下错误(使用 CUDA 10.1 的 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)
Run Code Online (Sandbox Code Playgroud)

的代码也许可以被改变,以避免这一点(例如,使用:

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)
Run Code Online (Sandbox Code Playgroud)

确保Range不是指针);但我现在无法做出改变。相反,我想以某种方式向编译器表明,我的真正意思是只有一个模板参数,而不是指定一个参数并推导出另一个模板参数。

我可以这样做吗?

感谢 C++11 和 C++14 的答案;涉及演绎指南的 C++17 答案不太相关,但如果您有,请发布(对于未来的 NVCC 版本......)


更新: strf 库本身已更新以规避这种情况,但问题仍然存在。

wal*_*nut 16

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);
}
Run Code Online (Sandbox Code Playgroud)

然后调用range1而不是strf::range.

range1_ptr<T>(...)总是可以用来显式调用带有一个模板参数的模板,但不从参数中进行任何推论。range1复制从原始strf::range模板的推论。

这是有效的,因为[temp.deduct.funcaddr]/1表示在获取没有转换目标类型的函数的地址时,模板参数推导是在每个候选函数模板上完成的,就好像假设调用的参数和参数列表是空的。因此,不能为具有两个模板参数的第二个重载推导出第二个模板参数。剩下的唯一候选是第一个重载,它将被选为函数指针的目标。

只要没有第二个候选函数模板可以形成只有一个参数的有效模板 ID,range1_ptr就可以始终使用明确地调用一个参数的函数模板。否则,实例化range1_ptr会因为歧义而报​​错。


max*_*x66 11

通过一个using?

using tfp = void(*)(char const *, char const *);

tfp x = &strf::range;

char const * a = "abcd";

(*x)(a, a+2);
Run Code Online (Sandbox Code Playgroud)