小编Max*_*hof的帖子

允许编译器对局部volatile进行常量折叠吗?

考虑以下简单代码:

void g();

void foo()
{
    volatile bool x = false;
    if (x)
        g();
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/I2kBY7

您可以看到,也gcc没有clang优化对的潜在调用g。在我的理解中,这是正确的:抽象机器假定volatile变量随时可能更改(由于例如被硬件映射),因此将false初始化不断折叠到if检查中将是错误的。

但是MSVC g完全消除了对的调用(保留对文件的读写volatile!)。这是符合标准的行为吗?


背景:我有时会使用这种结构来即时打开/关闭调试输出:编译器必须始终从内存中读取值,因此在调试过程中更改变量/内存应相应地修改控制流。 。MSVC输出确实重新读取了该值,但忽略了该值(可能是由于不断折叠和/或消除了死代码),这当然违背了我的意图。


编辑:

  • volatile这里讨论了对读写的消除:是否允许编译器优化局部volatile变量?(感谢内森!)。我认为该标准非常明确,即必须进行那些读写操作。但是,该讨论并未涵盖编译器将这些读取结果视为理所当然并基于此进行优化是否合法。我想这在标准中未指定/未指定,但是如果有人证明我做错了,我会很高兴。

  • 我当然可以制作x一个非局部变量来避免该问题。这个问题更多是出于好奇。

c++ volatile language-lawyer

25
推荐指数
1
解决办法
487
查看次数

为什么 {} 作为函数参数不会导致歧义?

考虑这个代码:

#include <vector>
#include <iostream>

enum class A
{
  X, Y
};

struct Test
{
  Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
  { std::cout << "vector overload" << std::endl; }

  Test(const std::vector<double>&, int, A = A::X)
  { std::cout << "int overload" << std::endl; }
};

int main()
{
  std::vector<double> v;
  Test t1(v);
  Test t2(v, {}, A::X);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/Gc_w8i

这打印:

vector overload
int overload
Run Code Online (Sandbox Code Playgroud)

为什么由于重载解析不明确而不会产生编译错误?如果删除第二个构造函数,我们会得到vector overload两次。如何/由什么指标是int一个明确更好地匹配了{}std::vector<int>

构造函数签名当然可以进一步修剪,但我只是被一段等效的代码所欺骗,并想确保这个问题没有丢失任何重要的东西。

c++ language-lawyer overload-resolution

20
推荐指数
1
解决办法
342
查看次数

具有默认参数的SFINAE函数 - 自由函数与运算符()

我正在玩这个答案来研究它如何使用默认参数处理函数.令我惊讶的是,自由函数的结果是不同的operator():

template <typename F>
auto func(F f) -> decltype(f(42))
{
    int a = 51;
    return f(51);
}

template <typename F>
auto func(F f) -> decltype(f(42, 42))
{
    int a = 0;
    int b = 10;
    return f(a, b);
}

int defaultFree(int a, int b = 0)
{
    return a;
}

auto defaultLambda = [](int a, int b = 0)
{
    return a;
};

int foo()
{
    return func(defaultFree);  
    //return func(defaultLambda);
}
Run Code Online (Sandbox Code Playgroud)

Godbolt链接

上述func(defaultFree)版本在两个func …

c++ sfinae language-lawyer c++11

19
推荐指数
2
解决办法
673
查看次数

可变参数模板仅在向前声明时编译

I have a variadic template that inherits from all template arguments:

template <typename... Ts>
struct derived : Ts...
{
};
Run Code Online (Sandbox Code Playgroud)

I would also like to have a facility for expressing the type of "existing derived with added template arguments". My attempt at this is:

// Do not ODR-use (goes in namespace impl or similar)!
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
    -> derived<ExistingInputs..., NewInputs...>;

template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
Run Code Online (Sandbox Code Playgroud)

As a simple example, Added<derived<A, …

c++ forward-declaration language-lawyer variadic-templates c++17

17
推荐指数
1
解决办法
308
查看次数

C++20 后友元声明中的模板特化

上下文:令我们惊讶的是,启用 C++20 模式和两阶段合规性的 MSVC 接受以下代码:

\n
template<class T>\nclass X\n{\n    friend int foo<X>(X x);\n\n    int a = 10;\n};\n\ntemplate <class T>\nint foo(T t)\n{\n    return t.a;\n}\n\nint main()\n{\n    return foo(X<float>{});\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这会编译/链接并10在 MSVC 和 gcc 中返回(但会发出 clang 声): https: //godbolt.org/z/98cd7v7a6

\n

那些了解两阶段查找的人会发现这看起来非常疯狂 - 我们可以在声明相应的模板之前以某种方式与模板专门化成为朋友。看起来和听起来都很不对劲。事实上,对于早期的 C++ 版本,所有编译器都会立即拒绝它: https: //godbolt.org/z/M1733EPd5

\n

但 C++20 中的以下措辞似乎为此铺平了道路(或者至少使其从一开始就不是完全错误的):https://timsong-cpp.github.io/cppwp/n4861/temp .names#2.sentence-4(强调我的)

\n
\n

如果名称是一个 unqualified-id 后跟一个名称,则该名称也被视为引用模板,并且<名称查找要么找到一个或多个函数,要么什么也没找到

\n
\n

现在,这导致了一大堆……好吧,荒谬的极端情况。请注意,在声明之外,friend您必须以 开始模板专门化template<>,但声明中的情况并非如此friend。可以预见的是,编译器甚至无法就现在合法和不合法的内容达成一致:

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
交朋友...神箭 …

c++ friend template-specialization language-lawyer c++20

17
推荐指数
2
解决办法
337
查看次数

是否可以在C ++标准库中实现always_false?

在某些情况下,如果尝试实例化某些模板,则使用always_false助手来导致无条件static_assert失败:

template <class... T> struct always_false : std::false_type {};

template<class T>
struct UsingThisShouldBeAnError {
  static_assert(always_false<T>::value, "You should not use this!");
};
Run Code Online (Sandbox Code Playgroud)

该帮助程序是必需的,因为模板定义必须(至少在理论上)具有至少一组模板参数,可以为其生成有效的专业化名称,以便程序格式正确:

[temp.res] / 8:如果满足以下条件,则该程序格式错误,无需进行诊断:

  • 无法为模板生成有效的专业化,并且模板没有实例化,或者

[...]

static_assert(false, "You should not use this!");因此,上面的书写格式不正确,即使没有实例化模板,编译器也总是可以触发静态断言,这不是故意的。)

这是涉及此模式的问题的快速样本(包括进一步的解释):

always_false作为标准库中的工具可能会很有用,因此我们不必不断地编写它。但是,以下问题的答案使我怀疑这是否可能:

从属非类型参数包:标准怎么说?

在那里(std::enable_if_t<T>总是关于[temp.res] / 8)产生一个论点,该论点始终是void或不是一种类型,任何人对其进行进一步专门化都是非法的。因此,依赖于理论上的“ std::enable_if特殊性”的模板可避免[temp.res] / 8子句,实际上会使程序格式错误,不需要诊断。

回到我的问题:如果提供了该标准always_false,它将不得不禁止图书馆用户照常对其进行专业化(出于明显的原因)。但是,根据上述推理,这将使always_false(在理论上可以专门用于除以外的东西std::false_type)整个观点破灭-关于[temp.res] / 8,它将与std::false_type直接使用相同。

我在这个推理上错了吗?还是标准库实际上不可能以always_false有意义/有用的方式提供(无需更改核心语言)?

c++ templates template-specialization

15
推荐指数
2
解决办法
227
查看次数

为什么不同的vector &lt;bool&gt;元素共享相同的地址?

我定义了以下课程。

class STTreeNode
{
public:
    int ind;
    int parentInd;  
    std::vector<int> childInds;

    int numTrain;
    std::vector<bool> isInfluenced;

    STTreeNode(int ind, int parentInd, int numTrain);
};

STTreeNode::STTreeNode(int ind, int parentInd, int numTrain) {
    this->ind = ind;
    this->parentInd = parentInd;
    this->numTrain = numTrain;
}

Run Code Online (Sandbox Code Playgroud)

我运行了以下代码段。

STTreeNode *a = new STTreeNode(3, 4, 5);
a->childInds.push_back(20);
a->childInds.push_back(30);
a->isInfluenced.push_back(true);
a->isInfluenced.push_back(false);

for (int i = 0; i < a->childInds.size(); i++)
    std::cout << &(a->childInds[i]) << " ";
std::cout << std::endl;
for (int i = 0; i < a->isInfluenced.size(); i++)
    std::cout << …
Run Code Online (Sandbox Code Playgroud)

c++

14
推荐指数
1
解决办法
686
查看次数

脱机成员函数定义是否需要使用低于全球范围的完全限定的类名?

这个问题让我想知道在类外成员函数定义中完全限定类名(包括全局作用域运算符)是否有用/必需。

一方面,我以前从未见过这样做(正确执行的语法似乎还不清楚)。另一方面,C ++名称查找非常简单,因此可能存在极端情况。

题:

是否曾经有过引入超出成员函数定义的定义
ReturnType (::Fully::Qualified::Class::Name::MemberFunctionName)(...) { ... }
不同于
ReturnType Fully::Qualified::Class::Name::MemberFunctionName(...) { ... }(没有全局作用域::前缀)的情况?

请注意,成员函数定义必须放在封闭类的名称空间中,因此不是有效的示例。

c++ qualified-name global-scope name-lookup scope-resolution-operator

14
推荐指数
2
解决办法
365
查看次数

如果琐碎的默认构造函数不执行任何操作,为什么不能使用malloc创建琐碎的可构造对象?

我很难理解cppreference引用的有关普通默认构造函数的以下段落。我已经搜索了stackoverflow,但仍然没有一个明确的答案。所以请帮忙。

普通的默认构造函数是不执行任何操作的构造函数。与C语言兼容的所有数据类型(POD类型)都是默认可构造的。但是,与C语言不同,不能通过简单地重新解释适当对齐的存储来创建具有琐碎默认构造函数的对象,例如,使用std :: malloc分配的内存:正式引入新对象并避免潜在的未定义行为时需要placement-new。

具体来说,如果琐碎的默认构造函数什么都不做,为什么我们不能重新解释存储并假装存在具有给定类型的对象?您能否提供一些可能导致未定义行为的示例?

c++ language-lawyer

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

const在这里允许(理论上)优化吗?

请考虑以下代码段:

void foo(const int&);

int bar();

int test1()
{
    int x = bar();
    int y = x;
    foo(x);
    return x - y;
}

int test2()
{
    const int x = bar();
    const int y = x;
    foo(x);
    return x - y;
}
Run Code Online (Sandbox Code Playgroud)

在我的标准的理解,既不x也没有y被允许通过改变footest2,而他们可以通过改变footest1(具有例如const_cast除去constconst int&是因为引用的对象实际上并不是常量中test1)。

现在,gcc,clang或MSVC似乎都没有优化test2foo(bar()); return 0;,并且我可以理解,他们不希望浪费优化来传递很少在实践中应用的优化。

但是我至少对我对这种情况的理解是正确的,还是我错过了一些法律x上的修改方法test2

c++ const compiler-optimization language-lawyer

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