小编zen*_*hoy的帖子

为什么我的SFINAE表达式不再适用于GCC 8.2?

我最近将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)

C++(gcc) - 在线试用

C++(clang) - 在线尝试

较旧版本的GCC(遗憾的是我不记得我之前安装的确切版本)以及Clang编译上面的代码就好了,但是GCC 8.2给出了一个错误说明:

 : In function 'int main()':
:29:19: error: call …

c++ gcc sfinae language-lawyer c++11

19
推荐指数
1
解决办法
1216
查看次数

如何实现一个避免未定义行为的侵入式链表?

几年来我第三次发现自己需要一个不允许提升的项目的侵入性链表(问管理......).

我第三次发现侵入式链表实现我的工作完美,但我真的不喜欢它使用未定义的行为 - 即将指针转换为列表节点到指向包含该列表的对象的指针列表节点.

那可怕的代码目前看起来像这样:

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年 - 有没有办法在不调用未定义的行为的情况下做到这一点?


编辑:评论中有一些建议的解决方案(涉及列表的不同结构),我想在这里总结一下:

  1. 生活在未定义的行为中,因为该语言具有看似任意的限制,可以防止反向使用成员指针.

  2. 在其中存储指向包含类的附加指针IntrusiveListNode.这当前可能是最干净的解决方案(不需要更改接口),但确实需要在每个列表节点中使用第三个指针(可能有小的优化).

  3. 衍生IntrusiveListNode和使用static_cast.在boost中,这是base_hook一个侵入式链表的版本.我想坚持使用该member_hook版本以避免引入多重继承.

  4. 存储指向下一个和上一个包含类的指针,而不是指向其中的下一个和上一个列表节点IntrusiveListNode.这使得在侵入列表中创建根节点变得困难.列表必须包括完整的实例化T(这是不可能的,例如,如果T是抽象的),或者列表的末尾需要是空指针(它将中断--list.end(),仅允许前向迭代).

  5. 提升侵入列表有一个member_hook版本可以某种方式工作,但实现尚未被理解(它可能还依赖于未定义的行为). …

c++ c++11

15
推荐指数
1
解决办法
1318
查看次数

std::is_constructible 为私有构造函数返回不一致的值

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默认不可构造。

取消注释注释行,它会打印11ideone),因此T突然变得默认可构造。

我可以找到支持这两个结果的推理,但我不明白包含注释行如何改变第二个结果。这是以某种方式调用UB吗?这是编译器错误吗?还是std::is_constructible真的那么矛盾?

c++ type-traits

13
推荐指数
1
解决办法
221
查看次数

可以将随机访问迭代器结束递增0吗?

标题说明了一切.给定一个结束的迭代器,它可以在不调用未定义的行为的情况下递增零吗?

例证 - 以下代码是否可以将迭代器返回到指定的索引 - 或者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::advancestd::next不同的行为也很有趣,但在这里我特别感兴趣operator+.

c++ iterator language-lawyer

11
推荐指数
1
解决办法
188
查看次数

type,value_type和element_type之间有什么区别,以及何时使用每个?

我编写了一个模板类,它应该公开它的模板参数,但我不确定它是否适当命名.

我找到了三个不同的名字,基本上是相同的东西(据我所知):

  • 容器,例如,std::vector使用value_type
  • 智能指针,例如,std::unique_ptr使用element_type
  • std::reference_wrapper 只使用 type

这些不同名字背后的想法是什么?什么标准算法或特征类取决于哪个名称?我应该为我的班级使用哪个名称(智能指针和参考包装器之间的东西)?

c++ c++11

11
推荐指数
2
解决办法
2066
查看次数

GCC关于隐式解除引用的警告

我在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)

有任何想法吗?

谢谢!

c++ gcc gcc-warning

9
推荐指数
1
解决办法
1892
查看次数

在输入流中搜索字符串

我有一个大的二进制文件(许多千兆字节,所以加载到内存中不是一个选项),我想搜索所有出现的字符串"icpf".

我尝试使用std::search它,但只是因为std::search只适用于前向迭代器,而不是输入迭代器这一事实.

标准库是否为此提供了快速替代方案?或者我是否需要手动编码搜索(一次读取块然后读取std::search,或者ignore直到'i'然后手动检查接下来的三个字符)?

c++ iostream

9
推荐指数
1
解决办法
1462
查看次数

有效地将双倍除以2的幂

我正在实现相干噪声函数,并且惊讶地发现使用梯度噪声(即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组装解决方案就可以了.

c c++ x86

8
推荐指数
1
解决办法
1447
查看次数

使用-pedantic进行编译时使用std :: reference_wrapper的不明确的构造函数

我有一个类,复制构造函数和构造函数采用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)

c++ copy-constructor reference-wrapper gcc-pedantic

8
推荐指数
1
解决办法
177
查看次数

这个检测整数加法溢出的函数实际上有用吗?

在阅读这个问题的评论时,我遇到了一个指向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 c++ integer-overflow

7
推荐指数
1
解决办法
189
查看次数