[英]Clang & GCC misdeducing template parameters
我不擅长C ++,因此这可能是新手错误。 我正在尝试创建一个异构链表类型,其中每个节点的类型以及其余列表的类型在每个节点中都是已知的。
这是一个SSSCE:
#include <utility>
template<typename T, typename... Rest>
struct hnode {
T data;
hnode<Rest...>* next;
};
template<typename T>
struct hnode<T> {
T data;
std::nullptr_t next;
};
template<typename T, typename... Rest>
hnode<T> hcons(T&& val, std::nullptr_t) {
return { std::forward<T>(val), nullptr };
}
template<typename T, typename... Rest>
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
return { std::forward<T>(val), &next };
}
int main() {
hnode<int> three = hcons(1, nullptr);
auto two = hcons("hi", three);
}
但是,GCC给我该代码的错误:
test.cc: In function ‘int main()’:
test.cc:28:29: error: no matching function for call to ‘hcons(const char [3], hnode<int>&)’
auto two = hcons("hi", three);
^
test.cc:28:29: note: candidates are:
test.cc:17:10: note: template<class T, class ... Rest> hnode<T> hcons(T&&, std::nullptr_t)
hnode<T> hcons(T&& val, std::nullptr_t) {
^
test.cc:17:10: note: template argument deduction/substitution failed:
test.cc:28:29: note: cannot convert ‘three’ (type ‘hnode<int>’) to type ‘std::nullptr_t’
auto two = hcons("hi", three);
^
test.cc:22:19: note: hnode<T, Rest ...> hcons(T&&, hnode<Rest ...>&) [with T = const char (&)[3]; Rest = {int, Rest}]
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
^
test.cc:22:19: note: no known conversion for argument 2 from ‘hnode<int>’ to ‘hnode<int, Rest>&’
Clang稍微简洁一些,但仍不足以帮助我修复它:
test.cc:28:12: error: no matching function for call to 'hcons'
auto two = hcons("hi", three);
^~~~~
test.cc:17:10: note: candidate function [with T = char const (&)[3], Rest = <>] not viable: no known conversion from 'hnode<int>' to 'std::nullptr_t' (aka 'nullptr_t') for 2nd argument
hnode<T> hcons(T&& val, std::nullptr_t) {
^
test.cc:22:19: note: candidate template ignored: substitution failure [with T = char const (&)[3], Rest = <>]: too few template arguments for class template 'hnode'
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
^ ~~~~~
1 error generated.
这似乎不可思议,因为它演绎Rest
是<>
时,应明确是<int>
,它说,这是<int>
上面用线no known conversion from 'hnode<int>' to 'std::nullptr_t'
。 我犯了什么错误?
尽管galop1n的答案是有效的解决方法,但它不能解决代码中的实际问题。
尽管我不是C ++语言律师或其他任何人,但是我在SO的某处读到模板匹配是一个相当严格的过程。 反思原始代码:在hcons
函数中,您要求编译器next
其匹配(应该是hnode<typename...>
类型)与hnode<typename, typename...>
。 可以想象,这并不是完全匹配。 它也与您的1个参数专业化(即hnode<typename>
不匹配。
为了使您的代码编译,您只需要更改1件事,那就是提供一个空的hnode
声明以接受可变数量的模板参数,并将其专门用于1参数版本和多参数版本:
#include <utility>
// empty declaration with variable number of arguments
template<typename...>
struct hnode;
// specialization for 1 template argument
template<typename T>
struct hnode<T> {
T data;
std::nullptr_t next;
};
// specialization for multiple template arguments
template<typename T, typename... Rest>
struct hnode<T, Rest...> {
T data;
hnode<Rest...>* next;
};
template<typename T>
hnode<T> hcons(T&& val, std::nullptr_t) {
return { std::forward<T>(val), nullptr };
}
template<typename T, typename... Rest>
hnode<T, Rest...> hcons(T&& val, hnode<Rest...>& next) {
return { std::forward<T>(val), &next };
}
int main() {
hnode<int> three = hcons(1, nullptr);
auto two = hcons("hi", three);
}
现在,您的hcons
函数可以完全匹配hnode<typename...>
,并将实例化相应的专业化。 乙二酮的POC
众所周知,Visual Studio的编译器在与模板相关的内容上有些松懈,所以这可能就是为什么它接受原始代码的原因。
从这个相关问题中可以发现,事实证明这是GCC和Clang中的错误,因此VS是正确接受您代码的代码。
另外,作为一个侧面说明:通过删除std::nullptr_t
在你的论点1专业化成员hnode
,可以节省一点点内存。
不知道为什么,但是由于hnode具有至少一个模板参数,因此可以:
#include <utility>
template<typename T, typename... Rest>
struct hnode {
T data;
hnode<Rest...>* next;
};
template<typename T>
struct hnode<T> {
T data;
std::nullptr_t next;
};
template<typename T>
hnode<T> hcons(T&& val, std::nullptr_t) {
return { std::forward<T>(val), nullptr };
}
template<typename T, typename S, typename... Rest>
hnode<T, S, Rest...> hcons(T&& val, hnode<S, Rest...>& next) {
return { std::forward<T>(val), &next };
}
int main() {
hnode<int> three = hcons(1, nullptr);
auto two = hcons("hi", three);
auto one = hcons(5.14f, two);
}
在您的版本上,一旦找不到最佳匹配,通常编译器会列出所有候选对象。 真正的问题仍然存在,为什么clang在模板参数包推导上是错误的...
Visual Studio 2013在两个版本(带有和不带有S)上都成功,但是在const char(*)[3]的前面却失败了,我用int代替了测试…
我不知道是Clang还是Visual,是对的,但在此处填写错误报告可能是一个好主意。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.