我最近将GCC升级到8.2,我的大多数SFINAE表达式都停止了工作.
以下是一些简化,但演示了问题:
#include <iostream>
#include <type_traits>
class Class {
public:
template <
typename U,
typename std::enable_if<
std::is_const<typename std::remove_reference<U>::type>::value, int
>::type...
>
void test() {
std::cout << "Constant" << std::endl;
}
template <
typename U,
typename std::enable_if<
!std::is_const<typename std::remove_reference<U>::type>::value, int
>::type...
>
void test() {
std::cout << "Mutable" << std::endl;
}
};
int main() {
Class c;
c.test<int &>();
c.test<int const &>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
较旧版本的GCC(遗憾的是我不记得我之前安装的确切版本)以及Clang编译上面的代码就好了,但是GCC 8.2给出了一个错误说明:
: In function 'int main()': :29:19: error: call …
几年来我第三次发现自己需要一个不允许提升的项目的侵入性链表(问管理......).
我第三次发现侵入式链表实现我的工作完美,但我真的不喜欢它使用未定义的行为 - 即将指针转换为列表节点到指向包含该列表的对象的指针列表节点.
那可怕的代码目前看起来像这样:
struct IntrusiveListNode {
IntrusiveListNode * next_;
IntrusiveListNode * prev_;
};
template <typename T, IntrusiveListNode T::*member>
class IntrusiveList {
// snip ...
private:
T & nodeToItem_(IntrusiveListNode & node) {
return *(T*)(((char*)&node)-((size_t)&(((T*)nullptr)->*member)));
}
IntrusiveListNode root_;
};
Run Code Online (Sandbox Code Playgroud)
我真的不在乎多么丑陋nodeToItem_,但我想保持公共接口和语法IntrusiveList相同.具体来说,我想指定列表类型的类型IntrusiveList<Test, &Test::node_>而不是IntrusiveList<Test, offsetof(Test, node_)>.
这几乎是2016年 - 有没有办法在不调用未定义的行为的情况下做到这一点?
编辑:评论中有一些建议的解决方案(涉及列表的不同结构),我想在这里总结一下:
生活在未定义的行为中,因为该语言具有看似任意的限制,可以防止反向使用成员指针.
在其中存储指向包含类的附加指针IntrusiveListNode.这当前可能是最干净的解决方案(不需要更改接口),但确实需要在每个列表节点中使用第三个指针(可能有小的优化).
衍生IntrusiveListNode和使用static_cast.在boost中,这是base_hook一个侵入式链表的版本.我想坚持使用该member_hook版本以避免引入多重继承.
存储指向下一个和上一个包含类的指针,而不是指向其中的下一个和上一个列表节点IntrusiveListNode.这使得在侵入列表中创建根节点变得困难.列表必须包括完整的实例化T(这是不可能的,例如,如果T是抽象的),或者列表的末尾需要是空指针(它将中断--list.end(),仅允许前向迭代).
提升侵入列表有一个member_hook版本可以某种方式工作,但实现尚未被理解(它可能还依赖于未定义的行为). …
std::is_constructible处理私有构造函数的规则是什么?鉴于以下代码:
#include <iostream>
class Class {
private:
Class() { }
};
template <typename T>
class Test {
public:
static void test() {
std::cout
//<< std::is_constructible<Class>::value
<< std::is_constructible<T>::value
<< std::endl;
}
};
int main() {
Test<Class>::test();
}
Run Code Online (Sandbox Code Playgroud)
这会打印0( ideone ),即T默认不可构造。
取消注释注释行,它会打印11(ideone),因此T突然变得默认可构造。
我可以找到支持这两个结果的推理,但我不明白包含注释行如何改变第二个结果。这是以某种方式调用UB吗?这是编译器错误吗?还是std::is_constructible真的那么矛盾?
标题说明了一切.给定一个结束的迭代器,它可以在不调用未定义的行为的情况下递增零吗?
例证 - 以下代码是否可以将迭代器返回到指定的索引 - 或者end索引是否超出范围?
std::vector<Type>::iterator Class::fromIndex(size_t index) {
return member_vector.begin() + std::min(index, member_vector.size());
}
Run Code Online (Sandbox Code Playgroud)
如果知道的行为std::advance或std::next不同的行为也很有趣,但在这里我特别感兴趣operator+.
我编写了一个模板类,它应该公开它的模板参数,但我不确定它是否适当命名.
我找到了三个不同的名字,基本上是相同的东西(据我所知):
std::vector使用value_typestd::unique_ptr使用element_typestd::reference_wrapper 只使用 type这些不同名字背后的想法是什么?什么标准算法或特征类取决于哪个名称?我应该为我的班级使用哪个名称(智能指针和参考包装器之间的东西)?
我在GCC中遇到了以下警告:
warning: implicit dereference will not access object of type ‘volatile util::Yield’ in statement [enabled by default]
Run Code Online (Sandbox Code Playgroud)
在编译此代码时:
volatile util::Yield y1;
util::Yield y2;
y1 += y2; // <--- Warning triggered here.
Run Code Online (Sandbox Code Playgroud)
不幸的是,我不太明白GCC试图告诉我的是什么......
Yield类声明如下:
class Yield {
public:
Yield();
Yield &operator+=(Yield const &other);
Yield &operator+=(Yield const volatile &other);
Yield volatile &operator+=(Yield const &other) volatile;
Yield volatile &operator+=(Yield const volatile &other) volatile;
// Other operators snipped...
};
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
谢谢!
我有一个大的二进制文件(许多千兆字节,所以加载到内存中不是一个选项),我想搜索所有出现的字符串"icpf".
我尝试使用std::search它,但只是因为std::search只适用于前向迭代器,而不是输入迭代器这一事实.
标准库是否为此提供了快速替代方案?或者我是否需要手动编码搜索(一次读取块然后读取std::search,或者ignore直到'i'然后手动检查接下来的三个字符)?
我正在实现相干噪声函数,并且惊讶地发现使用梯度噪声(即Perlin噪声)实际上比值噪声稍快.分析表明,其原因是将随机int值转换为范围-1.0到1.0的两倍所需的除法:
static double noiseValueDouble(int seed, int x, int y, int z) {
return 1.0 - ((double)noiseValueInt(seed, x, y, z) / 1073741824.0);
}
Run Code Online (Sandbox Code Playgroud)
梯度噪声需要多次乘法,但由于预先计算的梯度表使用noiseValueInt直接计算表中的索引,并且不需要任何除法.所以我的问题是,考虑到除法是2(2 ^ 30)的幂,我怎么能使上述除法更有效率.
理论上,所有需要做的是从双的指数减去30,但这样做的蛮力(即位操作)会导致各种极端情况(INF,NAN,指数溢出等).一个x86组装解决方案就可以了.
我有一个类,复制构造函数和构造函数采用std::reference_wrapper:
#include <functional>
#include <iostream>
class Class {
public:
Class() {
std::cout << "Class()" << std::endl;
}
Class(Class const &) {
std::cout << "Class(Class const &)" << std::endl;
}
Class(std::reference_wrapper<Class>) {
std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
}
Class(std::reference_wrapper<const Class>) {
std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
}
};
int main() {
Class a;
Class b = a;
Class c = std::ref(a);
Class d = std::cref(a);
}
Run Code Online (Sandbox Code Playgroud)
当正常编译时(g++ --std=c++17 test.cpp),它按照需要工作,按顺序调用四个构造函数:
$ ./a.exe
Class()
Class(Class const &)
Class(std::reference_wrapper<Class>) …Run Code Online (Sandbox Code Playgroud) 在阅读这个问题的评论时,我遇到了一个指向comp.lang.c常见问题的链接,该链接显示了一个"小心添加功能",据称可以检测到整数溢出:
int
chkadd(int a, int b)
{
if (INT_MAX - b < a) {
fputs("int overflow\n", stderr);
return INT_MAX;
}
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
如果这不会溢出怎么样b == -1?如果假设是a并且b都是积极的,为什么要制造它们int而不是unsigned int首先?
c++ ×10
c++11 ×3
c ×2
gcc ×2
gcc-pedantic ×1
gcc-warning ×1
iostream ×1
iterator ×1
sfinae ×1
type-traits ×1
x86 ×1