模板模板参数的替换失败
Substitution failure for template template argument
我想要一个辅助函数来为我实例化一个 class。目前它不能在 clang 中编译(尽管它在 gcc 中编译工作),但我也需要它在 clang 中工作。目前我正在使用 clang version 6.0.0-1ubuntu2
.
我不确定为什么会失败,因为 gcc 能够检测到类型。我试着做 this post and playing around with it for a while but I keep running into a wall. MCVE available, or you can try it on coliru here:
的东西
#include <vector>
using namespace std;
template <typename T, template <typename> typename Container>
struct SomeClass {
SomeClass(const Container<T>& c) {
}
};
template <typename T, template <typename> typename C>
inline auto make_some_class(const C<T>& container) {
return SomeClass<T, C>(container);
}
int main() {
vector<int> ints;
auto stuff = make_some_class(ints);
}
main.cpp:19:18: error: no matching function for call to 'make_some_class'
auto stuff = make_some_class(ints);
^~~~~~~~~~~~~~~
main.cpp:12:13: note: candidate template ignored: substitution failure [with T = int]: template template argument has different template parameters than its corresponding template template parameter
inline auto make_some_class(const C<T>& container) {
^
1 error generated.
建议:试试
#include <vector>
template <template <typename...> typename Container, typename ... Ts>
struct SomeClass {
SomeClass(const Container<Ts...>& c) {
}
};
template <template <typename...> typename C, typename ... Ts>
inline auto make_some_class(const C<Ts...>& container) {
return SomeClass<C, Ts...>(container);
}
int main() {
std::vector<int> ints;
auto stuff = make_some_class(ints);
}
我的意思是...我想问题是 std::vector
不是接收 one 类型模板参数的容器;它是一个接收 two 类型模板参数的容器(第二个具有默认类型:std::allocator<T>
,其中 T
是第一个)。
所以建议是:使 SomeClass
更灵活,并能够接收带有可变参数模板类型列表的容器
template <typename...> typename Container
和对应的模板类型列表
typename ... Ts
如果你想要一个可变参数列表(Ts...
),你需要它在最后一个位置,所以你必须切换 Container
和 T
的位置(现在 Ts...
): 在 Container
之前和可变参数列表之后 Ts...
template <template <typename...> typename Container, typename ... Ts>
struct SomeClass {
SomeClass(const Container<Ts...>& c) {
}
};
并非严格要求,但为了统一起见,我建议以相同的方式重写 make_some_class()
(显然,在模板参数列表中的 Ts...
之前传递 C
)。
template <template <typename...> typename C, typename ... Ts>
inline auto make_some_class(const C<Ts...>& container) {
return SomeClass<C, Ts...>(container);
}
正如评论和 max66 中已经建议的那样,std::vector
有两个模板参数,value_type
和 allocator_type
。
在 C++17 之前,在这种情况下,我们必须显式地将两个参数写为模板模板参数,这在 C++17 中也适用:
template <typename T, template <typename V, typename Allocator = std::allocator<T>> typename Container>
struct SomeClass {
SomeClass(const Container<T>& c) {
}
};
template <typename T, template <typename V, typename Allocator = std::allocator<T>> typename C>
inline auto make_some_class(const C<T>& container) {
return SomeClass<T, C>(container);
}
顺便说一句,因为 C++17,"Matching template template parameters to compatible arguments" [P0522R0
] 被接受,如果您使用 C++17,您的代码是正确的。
但是 Clang 默认情况下仍然禁用此新功能,并且编译标志 -frelaxed-template-template-args
启用此功能。
让我们将其简化为:
template <template <typename> class C, typename T>
void foo(C<T> const&) { }
std::vector<int> v;
foo(v);
您会发现 gcc 可以编译,但 clang 不会。两者的原因都很有趣。
首先,回想一下 std::vector
是一个 class 模板,它采用 两个 模板参数:
template <typename T, typename Alloc = std::allocator<T>>
class vector { ... };
为什么 gcc 认为匹配 template <typename> class C
- 一个只有 一个 模板参数的模板?因为规则因 P0522R0 而改变。这是有道理的——我们可以使用 vector
就像它在普通代码中有一个类型参数一样,所以它应该能够匹配这样一个模板参数。
现在,为什么 clang 认为 vector
不 匹配?因为他们明确选择不采用此规则。来自 their docs:
(10): Despite being the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag -frelaxed-template-template-args
in Clang 4 onwards. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.
也就是说,它可能 。
当然,您可能只是想知道如何修复它。只需更改模板模板参数的声明 C
:
template <template <typename...> class C, typename T>
void foo(C<T> const&) { }
std::vector<int> v;
foo(v); // ok in both gcc and clang
我想要一个辅助函数来为我实例化一个 class。目前它不能在 clang 中编译(尽管它在 gcc 中编译工作),但我也需要它在 clang 中工作。目前我正在使用 clang version 6.0.0-1ubuntu2
.
我不确定为什么会失败,因为 gcc 能够检测到类型。我试着做 this post and playing around with it for a while but I keep running into a wall. MCVE available, or you can try it on coliru here:
的东西#include <vector>
using namespace std;
template <typename T, template <typename> typename Container>
struct SomeClass {
SomeClass(const Container<T>& c) {
}
};
template <typename T, template <typename> typename C>
inline auto make_some_class(const C<T>& container) {
return SomeClass<T, C>(container);
}
int main() {
vector<int> ints;
auto stuff = make_some_class(ints);
}
main.cpp:19:18: error: no matching function for call to 'make_some_class'
auto stuff = make_some_class(ints); ^~~~~~~~~~~~~~~
main.cpp:12:13: note: candidate template ignored: substitution failure [with T = int]: template template argument has different template parameters than its corresponding template template parameter
inline auto make_some_class(const C<T>& container) { ^
1 error generated.
建议:试试
#include <vector>
template <template <typename...> typename Container, typename ... Ts>
struct SomeClass {
SomeClass(const Container<Ts...>& c) {
}
};
template <template <typename...> typename C, typename ... Ts>
inline auto make_some_class(const C<Ts...>& container) {
return SomeClass<C, Ts...>(container);
}
int main() {
std::vector<int> ints;
auto stuff = make_some_class(ints);
}
我的意思是...我想问题是 std::vector
不是接收 one 类型模板参数的容器;它是一个接收 two 类型模板参数的容器(第二个具有默认类型:std::allocator<T>
,其中 T
是第一个)。
所以建议是:使 SomeClass
更灵活,并能够接收带有可变参数模板类型列表的容器
template <typename...> typename Container
和对应的模板类型列表
typename ... Ts
如果你想要一个可变参数列表(Ts...
),你需要它在最后一个位置,所以你必须切换 Container
和 T
的位置(现在 Ts...
): 在 Container
之前和可变参数列表之后 Ts...
template <template <typename...> typename Container, typename ... Ts>
struct SomeClass {
SomeClass(const Container<Ts...>& c) {
}
};
并非严格要求,但为了统一起见,我建议以相同的方式重写 make_some_class()
(显然,在模板参数列表中的 Ts...
之前传递 C
)。
template <template <typename...> typename C, typename ... Ts>
inline auto make_some_class(const C<Ts...>& container) {
return SomeClass<C, Ts...>(container);
}
正如评论和 max66 中已经建议的那样,std::vector
有两个模板参数,value_type
和 allocator_type
。
在 C++17 之前,在这种情况下,我们必须显式地将两个参数写为模板模板参数,这在 C++17 中也适用:
template <typename T, template <typename V, typename Allocator = std::allocator<T>> typename Container>
struct SomeClass {
SomeClass(const Container<T>& c) {
}
};
template <typename T, template <typename V, typename Allocator = std::allocator<T>> typename C>
inline auto make_some_class(const C<T>& container) {
return SomeClass<T, C>(container);
}
顺便说一句,因为 C++17,"Matching template template parameters to compatible arguments" [P0522R0
] 被接受,如果您使用 C++17,您的代码是正确的。
但是 Clang 默认情况下仍然禁用此新功能,并且编译标志 -frelaxed-template-template-args
启用此功能。
让我们将其简化为:
template <template <typename> class C, typename T>
void foo(C<T> const&) { }
std::vector<int> v;
foo(v);
您会发现 gcc 可以编译,但 clang 不会。两者的原因都很有趣。
首先,回想一下 std::vector
是一个 class 模板,它采用 两个 模板参数:
template <typename T, typename Alloc = std::allocator<T>>
class vector { ... };
为什么 gcc 认为匹配 template <typename> class C
- 一个只有 一个 模板参数的模板?因为规则因 P0522R0 而改变。这是有道理的——我们可以使用 vector
就像它在普通代码中有一个类型参数一样,所以它应该能够匹配这样一个模板参数。
现在,为什么 clang 认为 vector
不 匹配?因为他们明确选择不采用此规则。来自 their docs:
(10): Despite being the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag
-frelaxed-template-template-args
in Clang 4 onwards. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.
也就是说,它可能
当然,您可能只是想知道如何修复它。只需更改模板模板参数的声明 C
:
template <template <typename...> class C, typename T>
void foo(C<T> const&) { }
std::vector<int> v;
foo(v); // ok in both gcc and clang