我不擅长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 上的某个地方读到模板匹配是一个相当严格的过程。反射(reflection)您的原始代码:在您的 hcons
中函数,你要求编译器匹配 next
(应该是 hnode<typename...>
类型)到 hnode<typename, typename...>
.正如您可以想象的那样,这并不是真正的精确匹配。它也不符合您的 1 个参数特化,即 hnode<typename>
.
为了让你的代码通过编译,你只需要改变一件事,那就是提供一个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 on ideone
众所周知,Visual Studio 的编译器在处理与模板相关的内容时有点松懈,因此这可能是它接受您的原始代码的原因。
可以在 this 中找到相关问题,结果证明是 GCC 和 Clang 中的错误,因此 VS 是正确接受您的代码的那个。
另请注意:通过删除 std::nullptr_t
hnode
的第一个参数特化中的成员, 你可以节省一点内存。
关于c++ - Clang 和 GCC 误推模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21209401/