为什么 Clang++ 编译器无法编译以下可变参数模板代码?
Why does Clang++ compiler fail to compile the following variadic template code?
#include <string>
#include <iostream>
#include <tuple>
#include <utility>
template<typename... T> struct test {
using args_type = std::tuple<T...>;
args_type x;
template<std::size_t... I>
void callme(std::index_sequence<I...>) {
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
}
};
int main() {
}
错误信息是
clang-3.7 -std=gnu++1y -Wc++14-extensions test.cpp
test.cpp:15:56: error: expected ')'
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
^
test.cpp:15:20: note: to match this '('
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
^
1 error generated.
同样的代码似乎可以用 G++ 4.9.2 编译得很好。我还没有找到关于 Clang 的任何相关错误报告。
似乎是一个 Clang 错误,尽管此类伪析构函数名称的查找可能存在缺陷并且是开放 CWG 问题的主题,特别是 555 和 399。
扩展模式的有效位是
std::get<I>(x).std::tuple_element<I, args_type>::type::~type()
这里,.
和()
之间的位是一个伪析构函数名;合格的名称查找然后要求
If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier,
the type-names are looked up as types in the scope designated by the
nested-name-specifier. Similarly, in a qualified-id of the form:
nested-name-specifieropt class-name :: ~
class-name
the second class-name is looked up in the same scope as the first.
即type
在 std::tuple_element<I, args_type>
中查找,发现它引用某种类型。注意 class-name 是标识符的语法名称(和 simple-template-ids),不需要参考实际 class。 std::get<I>(x).std::tuple_element<I, args_type>::type::~type
然后引用 type
的析构函数。
使用辅助函数的解决方法:
template <typename T>
void destroy(T& p) {p.~T();}
template<typename... T> struct test {
using args_type = std::tuple<T...>;
args_type x;
template<std::size_t... I>
void callme(std::index_sequence<I...>) {
int _[] = {(destroy(std::get<I>(x)), 0)...};
}
};
有趣的是,来自 IBM mentioned a couple workarounds 的 hstong 效果更好。
int _[] = {(std::get<I>(x).::std::tuple_element<I, args_type>::type::~type(), true)...};
或
int _[] = {(std::get<I>(x).std::template tuple_element<I, args_type>::type::~type(), true)...};
#include <string>
#include <iostream>
#include <tuple>
#include <utility>
template<typename... T> struct test {
using args_type = std::tuple<T...>;
args_type x;
template<std::size_t... I>
void callme(std::index_sequence<I...>) {
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
}
};
int main() {
}
错误信息是
clang-3.7 -std=gnu++1y -Wc++14-extensions test.cpp
test.cpp:15:56: error: expected ')'
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
^
test.cpp:15:20: note: to match this '('
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
^
1 error generated.
同样的代码似乎可以用 G++ 4.9.2 编译得很好。我还没有找到关于 Clang 的任何相关错误报告。
似乎是一个 Clang 错误,尽管此类伪析构函数名称的查找可能存在缺陷并且是开放 CWG 问题的主题,特别是 555 和 399。
扩展模式的有效位是
std::get<I>(x).std::tuple_element<I, args_type>::type::~type()
这里,.
和()
之间的位是一个伪析构函数名;合格的名称查找然后要求
If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, the type-names are looked up as types in the scope designated by the nested-name-specifier. Similarly, in a qualified-id of the form:
nested-name-specifieropt class-name
:: ~
class-namethe second class-name is looked up in the same scope as the first.
即type
在 std::tuple_element<I, args_type>
中查找,发现它引用某种类型。注意 class-name 是标识符的语法名称(和 simple-template-ids),不需要参考实际 class。 std::get<I>(x).std::tuple_element<I, args_type>::type::~type
然后引用 type
的析构函数。
使用辅助函数的解决方法:
template <typename T>
void destroy(T& p) {p.~T();}
template<typename... T> struct test {
using args_type = std::tuple<T...>;
args_type x;
template<std::size_t... I>
void callme(std::index_sequence<I...>) {
int _[] = {(destroy(std::get<I>(x)), 0)...};
}
};
有趣的是,来自 IBM mentioned a couple workarounds 的 hstong 效果更好。
int _[] = {(std::get<I>(x).::std::tuple_element<I, args_type>::type::~type(), true)...};
或
int _[] = {(std::get<I>(x).std::template tuple_element<I, args_type>::type::~type(), true)...};