小编Pre*_*nik的帖子

程序在3个主要的C++编译器中以不同方式编译.哪一个是对的?

作为我前一个问题的一个有趣的后续(虽然不具有重大的实际意义): 为什么C++允许我们在声明变量时用括号括起变量名?

我发现将括号中的声明与注入的类名称功能相结合可能会导致有关编译器行为的惊人结果.

看看以下程序:

#include <iostream>
struct B
{
};

struct C
{
  C (){ std::cout << "C" << '\n'; }
  C (B *) { std::cout << "C (B *)" << '\n';}
};

B *y = nullptr;
int main()
{
  C::C (y);
}
Run Code Online (Sandbox Code Playgroud)
  1. 用g ++ 4.9.2编译给出了以下编译错误:

    main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
    
    Run Code Online (Sandbox Code Playgroud)
  2. 它与MSVC2013/2015成功编译并打印 C (B *)

  3. 它与clang 3.5成功编译并打印 C

因此,强制性问题是哪一个是正确的?:)

(我强烈倾向于clang版本和msvc方式停止声明变量后,只是在技术上改变类型,其typedef似乎有点奇怪)

c++ language-lawyer

116
推荐指数
2
解决办法
4815
查看次数

为什么C++允许我们在声明变量时用括号括起变量名?

例如,声明如下:

int (x) = 0;
Run Code Online (Sandbox Code Playgroud)

甚至是:

int (((x))) = 0;
Run Code Online (Sandbox Code Playgroud)

我偶然发现了这一点,因为在我的代码中我碰巧有一个类似于下面的片段:

struct B
{
};

struct C
{
  C (B *) {}
  void f () {};
};

int main()
{
  B *y;
  C (y);
}
Run Code Online (Sandbox Code Playgroud)

显然,我想构造一个对象C,然后在它的析构函数中做一些有用的东西.但是,当它发生时,编译器将其C (y);视为y带有类型的变量声明,C因此它会输出有关y重新定义的错误.有趣的是,如果我把它写成C (y).f ()或类似的东西C (static_cast<B*> (y))将按预期编译.当然,最好的现代解决方法是{}在构造函数调用中使用.

因此,当我在那之后发现,可以声明变量之类的int (x) = 0;甚至是,int (((x))) = 0;但我从未见过任何人实际使用这样的声明.所以我很感兴趣 - 这种可能性的目的是什么,因为现在我看到它只创造了类似于臭名昭着的"最令人烦恼的解析"的情况,并没有添加任何有用的东西?

c++ most-vexing-parse

81
推荐指数
2
解决办法
4725
查看次数

下面的代码应该按照C++标准编译吗?

#include <type_traits>

template <typename T>
struct C;

template<typename T1, typename T2>
using first = T1;

template <typename T>
struct C<first<T, std::enable_if_t<std::is_same<T, int>::value>>>
{
};

int main ()
{
}
Run Code Online (Sandbox Code Playgroud)

不同编译器编译的结果:

MSVC:

错误C2753:'C':部分特化与主模板的参数列表不匹配

GCC-4.9:

错误:部分特化'C'不专门化任何模板参数

clang所有版本:

错误:类模板部分特化没有专门化任何模板参数; 要定义主模板,请删除模板参数列表

gcc-5 +:成功编译

另外我想指出那些琐碎的专业化:

template<typename T>
struct C<T>
{
};
Run Code Online (Sandbox Code Playgroud)

成功地无法由gcc编译.因此,似乎它认为我原始示例中的专业化是非平凡的.所以我的问题是 - 这样的模式是否被C++标准明确禁止?

c++ gcc templates sfinae language-lawyer

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

以下程序是否应按标准编译?

在我发现MSVC和GCC(也可能是clang)之间在编译和链接相同代码时的不兼容之后,我很好奇这个程序是否实际编译和链接,因此它是MSVC中的错误(报告链接器错误)或应该我用不同的方式写它.该计划包括3个文件:

template <typename T>
struct A
{
    void func() {};
};

template <>
void A<int>::func ();
Run Code Online (Sandbox Code Playgroud)

A.cpp:

#include "C.h"
int main()
{
    A<int> x;
    x.func();
}
Run Code Online (Sandbox Code Playgroud)

B.cpp:

#include "C.h"
template <>
void A<int>::func()
{
}
Run Code Online (Sandbox Code Playgroud)

MSVC产生的链接器错误是:

A.obj:错误LNK2019:未解析的外部符号"public:void __thiscall A :: func(void)"

所以基本上它决定不在定义中创建符号B.cpp.让我强烈怀疑它是一个错误的东西是移动func结构定义的非特定定义,甚至将它放在特化声明之上使程序成功,但我想确定.

所以我的问题是 - 是否应该通过符合标准的编译器/链接器编译和链接此程序而不会出错?

c++ template-specialization visual-c++ class-template

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

如何测试标准库中是否定义了std :: remove_cvref?

我在这里看不到任何类似于功能测试宏的内容:https//en.cppreference.com/w/cpp/utility/feature_test

原始文件中似乎都没有提到这两个地方:http : //www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0550r2.pdf

测试__cplusplus也不适当,因为C ++ 20尚未发布,但该功能已经受支持。

功能测试宏支持会在以后的标准化过程中出现,还是增加得太小而不能成为功能测试宏的一部分,因此想要有条件地使用标准版本的人一定会回到老式的手动编译器版本检查中吗?

c++ c++-standard-library c++20

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

小于int的位字段是否应该是整体提升的主题?

假设我有以下内容struct:

struct A
{
    unsigned int a : 1;
    unsigned int b : 1;
};
Run Code Online (Sandbox Code Playgroud)

我感兴趣的是表达的类型a + b.虽然技术上比特字段的"类型"大小小于int整数提升可能应该发生,然后结果int就像它碰巧在gcc和clang中.

但是,由于不可能提取出精确类型的位域本身,并且它总是被推断为它的"大"类型(即unsigned int在这种情况下)是否正确,整体推广应该发生?因为我们实际上无法谈论比特字段的确切类型和大小,除非它们被推断为unsigned int在哪种情况下不应该进行整体提升.

(我的问题再一次源于MSVC碰巧认为unsigned int这种表达的类型)

c++ integer-promotion language-lawyer bit-fields visual-studio-2015

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

如何省略推导出的参数类型的完美转发?

假设我有一些函数是一个类型的参数类型(或几个参数类型),我想推断出它.我也希望基于rvalue或lvalue这一事实的不同行为.直接写出它会导致一个明显的(对于有经验的人)陷阱,因为完美的转发:

#include <iostream>
#include <vector>

template <typename T>
void f (T &&v) // thought to be rvalue version
{
   // some behavior based on the fact that v is rvalue
   auto p = std::move (v);
   (void) p;
}

template <typename T>
void f (const T &v) // never called
{  
   auto p = v;
   (void) p;
}

int main ()
{
    std::vector<int> x = {252, 135};
    auto &z = x;
    f (z);
    std::cout << x.size () << '\n'; // woah, …
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics perfect-forwarding c++11 template-argument-deduction

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

能够在lambda中使用非捕获局部变量的编译时特性有什么意义?

我注意到允许一个人使用未在lambda中捕获的变量的编译时特性,例如call sizeof,decltypefunctions,例如:

#include <iostream>
void f ()
{
}

int main()
{
  int y = 13;
  auto x = []{ return sizeof (decltype (y));};
  std::cout << x () << '\n';
}
Run Code Online (Sandbox Code Playgroud)

由于这两个g++clang++没有错误编译这个节目,我想这是标准允许.

这似乎有点误导我,即使我想不出任何会导致错误的特殊恶意案件.但我想知道这个功能的实际用例是什么?

c++ lambda capture c++11

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

如何严格定义功能模板显式实例化规则?

注意:这个问题是关于显式实例化的,而不是显式专业化的。

请看下面的例子:

template <bool A, typename X>
void f (X &x) {} // 1
template <bool A>
void f (int &x) {} // 2
template void f<true> (int &x); // 3
Run Code Online (Sandbox Code Playgroud)

假设我的最初目标是仅显式实例化第二个功能模板,A = true因此我编写line // 3。但是直观上,第一个定义也可以用line显式实例化,// 3这有点麻烦,因为我无法用当前的语法实际转义它,因为bool A在我的情况下无法推断出它。从理论上讲,我什至都不介意两个函数模板最终都被显式实例化,但是最有趣的部分是实际的编译结果。

(在编译成功的所有情况下,仅实例化第二个功能模板。)

  1. 原案。用msvc和编译clang。无法使用以下命令进行编译gcc

    错误:“ void f(int&)”的模版模板特殊性“ f”

  2. 在第一个功能模板中替换bool Abool A = truegcc即可对其进行编译。

  3. 替换X &xX &&x(转发参考)会使clang无法使用以下命令进行编译:

    错误:“ f”的显式实例化的部分排序不明确

这是最激烈的案例的演示。 …

c++ language-lawyer function-templates explicit-instantiation

5
推荐指数
1
解决办法
97
查看次数

重载std :: get for enum索引数组

我发现有一个类基本上就像std::array是一些枚举的类,但是很方便.我想这不是很难想象如何实现它,让我们说它有这样的签名:

class enum_array <typename EnumT, typename ValueT, size_t N>
Run Code Online (Sandbox Code Playgroud)

另一方面,在尝试实现所有标准std::array相关函数时,我注意到std::get为这样的类模板编写重载函数并不那么容易.

首先,我认为将std::get上述枚举的值作为模板参数是很自然的,因此大多数问题都出现了:

1)如果我想在课外定义这样的功能,我必须做以下事情:

namespace std {
template <EnumT Index, typename EnumT, typename ValueT, size_t N>
EnumT &get (enum_array<EnumT, ValueT, N> &val)  
Run Code Online (Sandbox Code Playgroud)

但是,EnumT当指定第一个模板参数时,问题引起的问题仍然未知,因此该模板实际上形成了错误

如果我放在EnumT Index参数列表的第二个或更多位置,那么就存在一个问题,我无法真正指定这个参数,并且必须在其中指定其他东西,这看起来不像普通的std::get调用std::array.

2)如果我定义get的内部函数enum_array类作为友元函数一切都会貌似除了罚款的事实,那么它会被放置在同一个命名空间中的类enum_array属.把它放进去namespace std并不是最好的设计.

所以我的问题是:可以std::get用我用C++模板机制为这样的类提到的方式重载enum参数吗?

(想要指出这个问题主要是出于好奇而引起的std::get,std::array在我看来,事后并不是最有用的功能)

c++ arrays enums templates c++11

4
推荐指数
1
解决办法
395
查看次数