也许我累了,但我坚持这个简单的部分专业化,这不起作用,因为non-type template argument specializes a template parameter with dependent type 'T'
:
template <typename T, T N> struct X;
template <typename T> struct X <T, 0>;
Run Code Online (Sandbox Code Playgroud)
更换0
的T(0)
,T{0}
或(T)0
没有帮助.那么这种专业化甚至可能吗?
首先是一些代码,然后是一些上下文,然后是问题:
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
鉴于类型A,B
,我关注的是确切的定义std::common_type<A,B>
,忽略了std::common_type<A...>
任意类型的可变参数A...
.所以让
using T = decltype(true ? std::declval<A>() : std::declval<B>());
using C = std::common_type<A,B>;
Run Code Online (Sandbox Code Playgroud)
现在,根据一些消息来源,我发现了以下关系(typename
为简洁而省略):
cppreference.com: C::type = std::decay<T>::type
cplusplus.com: C::type = T
GCC 4.8.1 <type_traits>
实施: C::type = std::decay<T>::type
如果T
有效,否则C
不包含::type
成员("SFINAE友好")
Clang 3.3 <type_traits>
实施: C::type = std::remove_reference<T>::type
我找到"SFINAE友好"版本的GCC的一个小细节,而std::remove_reference
和std::decay
实际上仅在内置阵列和功能,加上CV-资格有所区别,这再次我不关心了.所以我的问题是
应该是decay<T>::type
还是只是T
?使用的理由是decay<T>::type
什么?它只是关于表示结果,A() + B()
例如算术表达式吗?
例如,尝试了一下,我发现在"正义T
"定义的情况下,我们有
common_type<int&,int&> = int&
common_type<int&,long&> = long …
Run Code Online (Sandbox Code Playgroud) 这是Explicit ref-qualified转换运算符模板的后续操作.我已经尝试了许多不同的选项,我在这里给出了一些结果,试图看看最终是否有任何解决方案.
假设一个类(例如任何一个)需要以方便,安全(无意外)的方式提供转换到任何可能的类型,以保留移动语义.我可以想到四种不同的方式.
struct A
{
// explicit conversion operators (nice, safe?)
template<typename T> explicit operator T&& () &&;
template<typename T> explicit operator T& () &;
template<typename T> explicit operator const T& () const&;
// explicit member function (ugly, safe)
template<typename T> T&& cast() &&;
template<typename T> T& cast() &;
template<typename T> const T& cast() const&;
};
// explicit non-member function (ugly, safe)
template<typename T> T&& cast(A&&);
template<typename T> T& cast(A&);
template<typename T> const …
Run Code Online (Sandbox Code Playgroud) c++ implicit-conversion move-semantics explicit-conversion c++11
这是另一个问题的后续行动.它指的是同样的问题(我希望),但使用一个完全不同的例子来说明它.原因是在前面的示例中,只有实验性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
考虑以下:
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 …
模板别名是简化类型,如非常方便typename F <T>::type
,只是F <T>
,在那里T
和type
有型.
我想对模板做同样的事情,例如F <T>::map
,简化它们F <T>
,在哪里T
以及map
模板结构或别名.
例如,考虑以下定义:
template <bool B>
using expr = std::integral_constant <bool, B>;
template <bool B>
using _not = expr <!B>;
template <template <typename> class F>
struct neg_f
{
template <typename T>
using map = _not <F <T>{}>;
};
template <typename T>
pred = expr < /* ... T ... */ >; // e.g., pred = expr <true>;
template <template …
Run Code Online (Sandbox Code Playgroud) 这在clang 3.3中编译得很好:
template <typename T>
struct M;
template <typename R, typename C, typename... A>
struct M <R (C::*)(A...)> { };
template <typename R, typename C, typename... A>
struct M <R (C::*)(A...) &> { };
Run Code Online (Sandbox Code Playgroud)
但在gcc 4.8.1中失败了:
[...] error: redefinition of ‘struct M <R (C::*)(A ...)>’
struct M <R (C::*)(A...) &> { };
^
[...] error: previous definition of ‘struct M <R (C::*)(A ...)>’
struct M <R (C::*)(A...)> { };
^
Run Code Online (Sandbox Code Playgroud)
在不同的上下文中使用时,会导致各种意外的编译器行为,如崩溃或内部编译器错误.
我理解ref-qualified成员函数在标准中称为"*this的右值引用"(N2439),并受gcc 4.8.1支持.
这里的问题是将它们用作模板参数,其中gcc似乎不区分ref-qualified和普通成员函数类型.
clang的std库实现似乎检测是否支持此功能
__has_feature(cxx_reference_qualified_functions) …
Run Code Online (Sandbox Code Playgroud) 给出以下转换运算符
struct A
{
template<typename T> explicit operator T&& () &&;
template<typename T> explicit operator T& () &;
template<typename T> explicit operator const T& () const&;
};
struct B {};
Run Code Online (Sandbox Code Playgroud)
我希望以下转换都是有效的,但有些会给出编译错误(实例):
A a;
A&& ar = std::move(a);
A& al = a;
const A& ac = a;
B&& bm(std::move(a)); // 1. OK
B&& bt(A{}); // 2. OK
B&& br(ar); // 3. error: no viable conversion from A to B
B& bl(al); // 4. OK
const B& bz(al); // 5. …
Run Code Online (Sandbox Code Playgroud) c++ rvalue-reference conversion-operator c++11 ref-qualifier
关于ODR有很多问题,但是我找不到我要找的东西,所以如果这个副本或标题不合适就道歉.
考虑以下:
struct t {t(*id)();};
template<typename T>
t type() {return {type<T>};}
Run Code Online (Sandbox Code Playgroud)
这是我对每种类型定义唯一标识符的过度简化,希望在不同的编译单元中保持唯一.
特别地,给定一个具体的类型T
等std::string
,并且假定两个不同的编译单元包括在头文件上面的代码,我想表达
type<T>().id
Run Code Online (Sandbox Code Playgroud)
t(*)()
在两个单元中采用相同的值(类型),因此用作类型的唯一标识符T
.
该值是函数的地址type<T>
,所以问题是一个独特的功能,type<T>
在程序被保证一个定义规则.iso 3.2/3说
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义.
其中3.2/2
一个非重载函数,其名称显示为可能被评估的表达式或[...],使用的是odr,除非[...]
我假设一个函数是非内联的,如果它的地址被采用(虽然我在标准中找不到).
iso 3.2/5列出了许多例外,但对函数的唯一引用是
带有外部链接的内联函数,[...],非静态函数模板,类模板的成员函数,或者未指定某些模板参数的模板特化[...]
似乎没有一个在这里的情况.
一个可验证的示例将需要多个文件.事实上,DieterLücking给出了一个声称失败的例子,虽然它在我的情况下并没有失败(我没有采取任何形式的"保证").
那么,这是否有效?
c++ function-pointers one-definition-rule function-templates c++11