从Clang到g ++的一些C++ 11代码的端口
template<class T>
using value_t = typename T::value_type;
template<class>
struct S
{
using value_type = int;
static value_type const C = 0;
};
template<class T>
value_t<S<T>> // gcc error, typename S<T>::value_type does work
const S<T>::C;
int main()
{
static_assert(S<int>::C == 0, "");
}
Run Code Online (Sandbox Code Playgroud)
给出了Clang(版本3.1到SVN主干)与任何g ++版本的不同行为.对于后者我得到的错误,这样的
Run Code Online (Sandbox Code Playgroud)prog.cc:13:13: error: conflicting declaration 'value_t<S<T> > S< <template-parameter-1-1> >::C' const S<T>::C; ^ prog.cc:8:29: note: previous declaration as 'const value_type S< <template-parameter-1-1> >::C' static value_type const C = 0; ^ prog.cc:13:13: error: declaration …
似乎只能在别名模板的pack参数的位置扩展pack参数.对于类或函数模板,情况并非如此:
template <class T, class... Args> struct x { using type = T; };
template <class T, class... Args> using x_t = typename x<T, Args...>::type;
template <class... Args> using x_fix_t = typename x<Args...>::type;
template <class... Args> auto f(Args...) -> void {
typename x<Args...>::type v1; // OK
x_t<Args...> v2; // Error
x_fix_t<Args...> v3; // OK
}
Run Code Online (Sandbox Code Playgroud)
更简单的情况:
template <class T, class U> using y_t = T;
template <class... Args> auto f(Args...) -> void {
y_t<Args...> v4; // Error
} …Run Code Online (Sandbox Code Playgroud) c++ language-lawyer variadic-templates c++11 template-aliases
我可以使用模板别名作为模板模板参数吗?
template <template <typename...> class> struct foo {};
template <typename T> using simple_ptr = std::unique_ptr<T>;
foo<std::unique_ptr> a; // this doesn't work, std::unique_ptr has two parameters
foo<simple_ptr> b; // does this work?
Run Code Online (Sandbox Code Playgroud) 首先是一些代码,然后是一些上下文,然后是问题:
template <typename T> using id = T;
template <template <typename...> class F, typename... T>
using apply1 = F <T...>;
template <template <typename...> class F>
struct apply2
{
template <typename... T>
using map = F <T...>;
};
// ...
cout << apply1 <id, int>() << endl;
cout << apply2 <id>::map <int>() << endl;
Run Code Online (Sandbox Code Playgroud)
clang 3.3和gcc 4.8.1都编译了这个没有错误,应用了标识元函数int,因此两个表达式都计算为默认值int(零).
id有一段template <typename>时间的事实apply1,apply2期待template <typename...>我首先关注我.然而,这是很方便的,这个例子的作品,因为否则像元函数apply1,apply2必须是这么多参与.
另一方面,这样的模板别名在现实世界的代码中引起严重的问题,我无法在这里重现:gcc频繁的内部编译器错误,以及clang的频繁出现意外行为(仅在更高级的SFINAE测试中).
经过几个月的试验和错误,我现在安装并尝试(实验)gcc 4.9.0上的代码,这里出现错误:
test.cpp: …Run Code Online (Sandbox Code Playgroud) c++ template-meta-programming variadic-templates c++11 template-aliases
在C++ 11中,您可以通过执行类似的操作来创建"类型别名"
template <typename T>
using stringpair = std::pair<std::string, T>;
Run Code Online (Sandbox Code Playgroud)
但这与您期望的模板typedef看起来有所不同:
template <typename T>
typedef std::pair<std::string, T> stringpair;
Run Code Online (Sandbox Code Playgroud)
所以这提出了一个问题 - 为什么他们需要提出一个新的语法?什么是旧的typedef语法不起作用?
我意识到最后一点没有编译,但为什么不能编译?
我正在为g ++(版本4.8.1_1,Macports)和clang ++(版本3.3,Macports)编写一些TMP密码.虽然g ++拒绝使用UNBRIDLED FURY的以下代码清单,但是 clang ++会用优雅和辉煌来编译它.
这是代码清单,专为您而制作.
template <class... Ts>
struct sequence;
template <int T>
struct integer;
// This definition of `extents` causes g++ to issue a compile-time error.
template <int... Ts>
using extents = sequence<integer<Ts>...>;
// However, this definition works without any problems.
// template <int... Ts>
// struct extents;
template <int A, int B, class Current>
struct foo;
template <int A, int B, int... …Run Code Online (Sandbox Code Playgroud) c++ templates template-specialization c++11 template-aliases
这是另一个问题的后续行动.它指的是同样的问题(我希望),但使用一个完全不同的例子来说明它.原因是在前面的示例中,只有实验性GCC 4.9因编译器错误而失败.在此示例中,Clang和GCC 4.8.1也以不同方式失败:Clang产生意外结果,GCC 4.8.1报告不同的错误消息.
上一个问题的答案或多或少地说代码是有效的,问题在于GCC的实验版本.但这个结果让我更加怀疑.几个月来我一直困扰着我怀疑有相关(或相同)的问题,这是我第一次有一个小的具体例子来说明.
所以,这里有一些代码.首先,一些通用代码将SFINAE应用于由可变参数模板别名元函数指定的任意测试F:
#include <iostream>
using namespace std;
using _true = integral_constant <bool, true>;
using _false = integral_constant <bool, false>;
template <typename T> using pass = _true;
template <template <typename...> class F>
struct test
{
template <typename... A> static _false _(...);
template <typename... A> static pass <F <A...> > _(int);
};
template <template <typename...> class F, typename... A>
using sfinae = decltype(test <F>::template _<A...>(0));
Run Code Online (Sandbox Code Playgroud)
第二,一个特定的测试,检查给定的类是否定义了一个名为的类型type:
template <typename T> using type_of = …Run Code Online (Sandbox Code Playgroud) c++ templates template-meta-programming variadic-templates template-aliases
我将variadic模板解压缩到模板别名时遇到了问题.
以下代码适用于Clang 3.4和GCC 4.8,但在GCC 4.9中失败:
template <typename T, typename...>
using front_type = T;
template <typename... Ts>
struct foo
{
using front = front_type<Ts...>;
};
Run Code Online (Sandbox Code Playgroud)
GCC 4.9抱怨:
test.cc:7:37: error: pack expansion argument for non-pack parameter 'T' of alias template 'template<class T, class ...> using front_type = T'
using front = front_type<Ts...>;
^
test.cc:1:15: note: declared here
template <typename T, typename...>
^
Run Code Online (Sandbox Code Playgroud)
存在一个提交的GCC错误(#59498),但这应该失败吗?以下是C++核心语言#1430的一些上下文,"将扩展打包到固定别名模板参数列表":
最初,包扩展无法扩展到固定长度的模板参数列表,但在N2555中已更改.这适用于大多数模板,但会导致别名模板出现问题.
在大多数情况下,别名模板是透明的; 当它在模板中使用时,我们可以在依赖模板参数中替换.但是,如果template-id对非可变参数使用包扩展,则这不起作用.例如:
Run Code Online (Sandbox Code Playgroud)template<class T, class U, class V> struct S {}; template<class …
在C++ 03中,模板参数推导在某些上下文中不会发生.例如:
template <typename T> struct B {};
template <typename T>
struct A
{
typedef B<T> type;
};
template <typename T>
void f(typename A<T>::type);
int main()
{
B<int> b;
f(b); // ERROR: no match
}
Run Code Online (Sandbox Code Playgroud)
这里int不推断T,因为嵌套类型A<T>::type是非推断的上下文.
我是否写过这样的函数:
template <typename T> struct B {};
template <typename T>
void f(B<T>);
int main()
{
B<int> b;
f(b);
}
Run Code Online (Sandbox Code Playgroud)
一切都很好,因为B<T> 是推断的背景.
但是,在C++ 11中,模板别名可用于以类似于第二个示例的语法伪装嵌套类型.例如:
template <typename T> struct B {};
template <typename T>
struct A
{
typedef …Run Code Online (Sandbox Code Playgroud) 考虑以下:
template<typename X>
struct Z {};
struct A
{
using Z = ::Z<int>;
struct B : Z
{
using C = Z;
};
};
Run Code Online (Sandbox Code Playgroud)
编译好了.尼斯.但现在添加另一个参数Z:
template<typename X, typename Y>
struct Z {};
struct A
{
template<typename X>
using Z = ::Z<X, int>;
struct B : Z<B>
{
using C = Z<B>; // error: too few template arguments for class template 'Z'
};
};
Run Code Online (Sandbox Code Playgroud)
好吧,也许有意义的是,在派生嵌套类时Z,类中模板别名的定义A是可见的B,但在其体内却不可见,因为全局定义Z有两个参数,所以触发错误.
但是为什么第一种情况下的行为不同,何时Z只是一个类型别名A …
c++ ×10
template-aliases ×10
c++11 ×9
templates ×6
g++ ×1
gcc4.9 ×1
nested-class ×1
typedef ×1