在下面,GCC将模板结构name与name类的模板成员函数混淆A,而Clang编译精细(实例):
template<typename T>
struct name {};
struct A
{
template<bool B>
void name() { }
};
template<bool B, typename T>
void f(T& x) { x.template name<B>(); }
Run Code Online (Sandbox Code Playgroud)
函数f显然是A在本例中使用类型的参数调用,但它可能是其他任何东西,因此f需要保留模板函数.
我不关心哪个编译器是正确的,我只需要一个解决方法因为我真的不知道除了之外的任何语法
x.template name<B>();
Run Code Online (Sandbox Code Playgroud)
调用成员函数,我看不出using声明或任何其他消除歧义的方式如何适用.
编辑是的,我现在尝试了更明确的语法
x.T::template name<B>();
Run Code Online (Sandbox Code Playgroud)
哪个有效,但真的很难看.有什么办法让简短的语法有效吗?否则,最好将两个名称中的一个更改为......
EDIT2我原来的版本f作品上一个普遍的参考T&&,这需要最丑
using X = typename std::remove_reference<T>::type;
x.X::template name<B>();
Run Code Online (Sandbox Code Playgroud)
以防万一T是一个参考...而这一切都是为了一个简单的函数调用.
任何以某种形式使用泛型编程或模板元编程的人都遇到过诸如意外的长编译时间,大型可执行文件,深度嵌套的编译器错误消息或填写整个屏幕的类型名称等问题.
最近一个不幸的例子是未使用函数的"意外"实例化.仅仅为了动力,今天我还有另一个"意想不到的"系列活动:
T,正在测试一种类型std::is_empty;D,来自T;D符时,T实例化(用户定义的)泛型赋值运算符;std::enable_if,这种操作实例std::is_assignable <M, T>,其中M是一个部件或碱的类型T,并且在同一类模板的一个实例T;TR被实例化,T这需要std::is_empty <T>; 在这一点上,我得到一个错误,某些类型不完整.我可以通过一些特殊化来轻松修补它TR,因为std::is_empty在特定情况下并不需要."轻松"意味着大约需要两个小时来分析错误消息.有趣的是,当我从其他地方(一个"遥远的"基类T)中删除一个从未使用过的无条件赋值运算符时,所有这些都被揭示出来了.该补丁也加快了编译速度,但我不会调查它是否不是为了错误.
在过去,我已经看到编译时间下降,例如从小的或更大的补丁,从2分钟下降到10秒,随机出现或者有点想象力.
该问题是:是否有系统的方法或工具来控制,而等待我们的模板代码编译正在发生的事情,这将帮助我们改进,即使它使用的代码,类似于我们如何调试运行时程序?
我见过的唯一(或最好)工具是Templight,它与clang配合使用,需要编译器补丁.它的会议C++幻灯片看起来很酷,但在尝试之前,我会很感激任何相关的想法.
我发现的其他问题/资源就是例如
但是已经过时了.
c++ debugging templates compilation template-meta-programming
以下适用类型转换F到一个列表C的类型E...:
template <template <typename...> class F, typename P> struct apply_t;
template <
template <typename...> class F,
template <typename...> class C, typename... E
> struct apply_t <F, C <E...> > { typedef C <F <E>...> type; };
template <template <typename...> class F, typename P>
using apply = typename apply_t<F, P>::type;
Run Code Online (Sandbox Code Playgroud)
现在,给出这个输入:
template <typename T> using map1 = T*;
template <typename T> using map2 = const T;
template <typename T> using map3 = const T*;
Run Code Online (Sandbox Code Playgroud)
我在gcc …
在下面,struct Y重载了X成员函数f.两个重载都是模板函数,但是要明确指定不同的参数(typename和int):
struct X
{
template <typename> static bool f() { return true; }
};
struct Y : public X
{
using X::f;
template <int> static bool f() { return false; }
};
int main()
{
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
1 0按预期使用gcc 打印.然而,clang(3.3)抱怨说
[...] error: no matching function for call to 'f'
std::cout << Y::f <void>() << " " << Y::f …Run Code Online (Sandbox Code Playgroud) c++ overloading member-functions using-declaration template-function
我知道模板成员函数只有在使用时才会生成.如果不是所有使用的类型都支持这样的功能,这很方便.但是,这似乎不适用于具有尾随返回类型规范的函数.以下是一个小实验:
// helper function for case A workaround
template <typename A, typename T>
auto F(T&& x)
-> decltype(x.template f <A>())
{ return x.template f <A>(); }
// helper function for case B workaround
template <typename A, typename T>
auto G(T&& x)
-> decltype(x.g())
{ return x.g(); }
template <typename T>
struct S
{
// case A: not ok in GCC + Clang
template <typename A>
auto f1()
-> decltype(T().template f <A>())
{ return T().template f <A>(); }
// case A …Run Code Online (Sandbox Code Playgroud) 下列
int i = 0;
double d{i};
Run Code Online (Sandbox Code Playgroud)
给出 a 的错误(在 clang 中)或警告(在 gcc 中)narrowing conversion from 'int' to 'double'。我发现令人惊奇的是,这确实在缩小,至少在我看到从 unsigned 到 double 的缩小转换之前是这样。
我的实际问题源于一个包含数组并提供一个构造函数来以最简单的方式(转发)指定数组元素的类:
template<typename T, size_t N>
struct A
{
T a[N];
template<typename... E>
A(E&&... e) : a{std::forward<E>(e)...} { }
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们有以下内容(实例):
int i = 0;
A<double, 2> x(i, 2); // ERROR for both 'i' and '2'
double y[2]{i, 2}; // ERROR for 'i' only
Run Code Online (Sandbox Code Playgroud)
其中ERROR指的是如上所述的缩小转换。我怀疑所有这些错误都归结为开头提到的错误(double d{i};)。是这样吗?否则,会发生什么? …
这是一个简化的例子,代码用于生成任意值的序列(在某种意义上std::iota)和不同类别的迭代器:
struct delta
{
template<typename I>
void inc(I& i) { ++i; }
template<typename I>
I next(I i) { inc(i); return i; }
};
Run Code Online (Sandbox Code Playgroud)
有许多类,如delta,每一个都限定inc不同,例如--i,i += step,i -= step,i *= step,f(i)等功能next保持不变,实际上是在基类共享.
我们正在next从变异操作中产生基于价值的操作inc.相反的做法是相同的,但是我们选择这种设计来提高性能,因为next只能在某些初始化时inc调用,而可能被称为一百万次.
问题是,如果某些参数是编译时常量,我想next在编译时调用给定一个constexpr参数i.
这在C++ 11中是不可能的,因为调用了非constexpr函数inc.只需改为
template<typename I>
constexpr I next(I i) { inc(i); return i; …Run Code Online (Sandbox Code Playgroud) 我在嵌套命名空间中有一个模板类的前向声明
namespace n1
{
namespace n2
{
template <typename T, typename S>
struct A;
}
using n2::A;
}
Run Code Online (Sandbox Code Playgroud)
后跟一个定义,实际上是在一个不同的文件中,其间有东西:
struct X { };
namespace n1
{
namespace n2
{
template <typename T, typename S = X>
struct A { };
}
using n2::A;
}
Run Code Online (Sandbox Code Playgroud)
然后以下总是好的:
n1::n2::A <int> a;
Run Code Online (Sandbox Code Playgroud)
但这个捷径
n1::A <int> a;
Run Code Online (Sandbox Code Playgroud)
在clang中给出编译错误
error: too few template arguments for class template 'A'
Run Code Online (Sandbox Code Playgroud)
除非我删除了前瞻性声明; g ++接受两者.
clang似乎与第一个不包含默认模板参数的声明一致(我不能包含它,因为我还没有定义X).
如果我使用单个命名空间没有问题(但这不是一个解决方案).
我做错了什么,或者哪个编译器是正确的?快捷方式如何与前向声明和嵌套命名空间一起工作?我需要他们所有人.
XS的前向声明+默认参数当然有效,但实际上太繁琐(实际上有几十个,整个文件结构都会改变).
考虑F一个constexpr size_t参数的函数对象I
struct F
{
template <size_t I>
constexpr size_t operator()(size <I>) const { return I; }
};
Run Code Online (Sandbox Code Playgroud)
包裹在一个类型中size <I>,其中(为简洁起见)
template <size_t N>
using size = std::integral_constant <size_t, N>;
Run Code Online (Sandbox Code Playgroud)
当然,我们可以I直接传递,但我想通过使用它作为模板参数强调它是constexpr.函数F在这里是虚拟的,但实际上它可以做各种有用的东西,比如从I元组的元素中检索信息.F假定具有相同的返回类型,无论如何I.I可以是任何整数类型,但假设是非负的.
问题
给定一个constexpr size_t值I,我们可以调用F由
F()(size <I>());
Run Code Online (Sandbox Code Playgroud)
现在,如果我们想F用非constepr size_t值调用i怎么办?考虑以下:
constexpr size_t L = 10;
idx <F, L> f;
for (size_t i = …Run Code Online (Sandbox Code Playgroud) 在下面,static constexpr成员L在类中初始化A,然后通过值或(通用)引用传递.后者在Clang中失败但在GCC中失败,并且成员/非成员函数的行为略有不同.更详细:
#include <iostream>
using namespace std;
struct A
{
static constexpr size_t L = 4;
template <typename T>
void member_ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void member_val(T x) { cout << x << endl; }
};
template <typename T>
void ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void val(T x) { cout << x << endl; }
int main ()
{
A().member_ref(A::L); …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++11 ×5
templates ×4
constexpr ×3
arrays ×1
c++14 ×1
compilation ×1
debugging ×1
gcc ×1
inlining ×1
namespaces ×1
narrowing ×1
overloading ×1