如何防止 C++ 猜测第二个模板参数?
How can I prevent C++ guessing a second template argument?
我正在使用 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) { /* ... */ }
}
现在,我想在我的代码中使用 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)
库 代码可能会被更改以避免这种情况(例如使用:
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)
以确保 Range
不是指针);但我现在无法进行更改。相反,我想以某种方式向编译器表明我真正的意思是只有一个模板参数,而不是指定一个而推导另一个。
我可以这样做吗?
希望得到 C++11 和 C++14 的答案;涉及演绎指南的 C++17 答案不太相关,但如果你有,请post它(对于未来的 NVCC 版本......)
更新: strf 库本身已更新以规避这种情况,但问题仍然存在。
穿过 using
怎么样?
using tfp = void(*)(char const *, char const *);
tfp x = &strf::range;
char const * a = "abcd";
(*x)(a, a+2);
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);
}
然后调用 range1
而不是 strf::range
。
range1_ptr<T>(...)
始终可用于显式调用带有一个模板参数的模板,但不会从参数中进行任何推导。 range1
从原始 strf::range
模板复制推导。
这行得通,因为 [temp.deduct.funcaddr]/1 说,在获取没有转换目标类型的函数地址时,模板参数推导是在每个候选函数模板上完成的,就好像假设调用的参数和参数列表一样是空的。因此,对于具有两个模板参数的第二个重载,不能推导出第二个模板参数。剩下的唯一候选者是第一个重载,它将被选为函数指针的目标。
只要没有第二个候选函数模板可以形成一个有效的只有一个参数的模板id,range1_ptr
总是可以用来明确地调用一个参数的函数模板。否则实例化range1_ptr
会因为歧义而报错
一个解决方案是
1) 首先,您应该指定第二个参数的类型,例如(char *)(some_char_ptr + some_length)
2) 不要对两者都使用 const
,这很有效:
strf::range((char *)some_char_ptr, (char *)(some_char_ptr + some_length));
您可以尝试将左侧或右侧的(char *)
替换为(const char *)
,它仍然有效。
我正在使用 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) { /* ... */ }
}
现在,我想在我的代码中使用 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)
库 代码可能会被更改以避免这种情况(例如使用:
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)
以确保 Range
不是指针);但我现在无法进行更改。相反,我想以某种方式向编译器表明我真正的意思是只有一个模板参数,而不是指定一个而推导另一个。
我可以这样做吗?
希望得到 C++11 和 C++14 的答案;涉及演绎指南的 C++17 答案不太相关,但如果你有,请post它(对于未来的 NVCC 版本......)
更新: strf 库本身已更新以规避这种情况,但问题仍然存在。
穿过 using
怎么样?
using tfp = void(*)(char const *, char const *);
tfp x = &strf::range;
char const * a = "abcd";
(*x)(a, a+2);
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);
}
然后调用 range1
而不是 strf::range
。
range1_ptr<T>(...)
始终可用于显式调用带有一个模板参数的模板,但不会从参数中进行任何推导。 range1
从原始 strf::range
模板复制推导。
这行得通,因为 [temp.deduct.funcaddr]/1 说,在获取没有转换目标类型的函数地址时,模板参数推导是在每个候选函数模板上完成的,就好像假设调用的参数和参数列表一样是空的。因此,对于具有两个模板参数的第二个重载,不能推导出第二个模板参数。剩下的唯一候选者是第一个重载,它将被选为函数指针的目标。
只要没有第二个候选函数模板可以形成一个有效的只有一个参数的模板id,range1_ptr
总是可以用来明确地调用一个参数的函数模板。否则实例化range1_ptr
会因为歧义而报错
一个解决方案是
1) 首先,您应该指定第二个参数的类型,例如(char *)(some_char_ptr + some_length)
2) 不要对两者都使用 const
,这很有效:
strf::range((char *)some_char_ptr, (char *)(some_char_ptr + some_length));
您可以尝试将左侧或右侧的(char *)
替换为(const char *)
,它仍然有效。