小编Jon*_*eld的帖子

无法在函数内声明运算符.Clang bug或spec?

C的一个怪异角落案例是函数可以在其他函数中声明,例如

void foo(void)
{
  void bar(void); // Behaves as if this was written above void foo(void)
  bar();
}
Run Code Online (Sandbox Code Playgroud)

这已经贯彻到C++,至少对于大多数功能而言.如果有问题的函数恰好被称为operator ==,Clang似乎不会识别该模式.

struct foo
{
  int value;
};

struct bar
{
  foo value;
};

bool wot(const bar &x, const bar &y)
{
  bool eq(const foo &, const foo &);         // Declare function eq
  bool operator==(const foo &, const foo &); // Declare function operator==
  bool func = eq(x.value, y.value);          // This line compiles fine
  bool call = operator==(x.value, y.value);  // Also OK …
Run Code Online (Sandbox Code Playgroud)

c++ infix-notation clang language-lawyer name-lookup

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

没有堆的pimpl.不正确还是迷信?

我渴望将接口与实现分开.这主要是为了保护使用库的代码来改变所述库的实现,尽管减少编译时间肯定是受欢迎的.

对此的标准解决方案是指向实现习惯用法的指针,最有可能通过使用unique_ptr并使用实现仔细定义类析构函数来实现.

这不可避免地引起了对堆分配的担忧.我熟悉"让它工作,然后快速完成","简介再优化"等智慧.还有在线文章,例如gotw,它宣称明显的解决方法是脆弱和不可移植.我有一个目前不包含任何堆分配的库 - 我想保持这种方式 - 所以让我们有一些代码.

#ifndef PIMPL_HPP
#define PIMPL_HPP
#include <cstddef>

namespace detail
{
// Keeping these up to date is unfortunate
// More hassle when supporting various platforms
// with different ideas about these values.
const std::size_t capacity = 24;
const std::size_t alignment = 8;
}

class example final
{
 public:
  // Constructors
  example();
  example(int);

  // Some methods
  void first_method(int);
  int second_method();

  // Set of standard operations
  ~example();
  example(const example &);
  example &operator=(const example &); …
Run Code Online (Sandbox Code Playgroud)

c++ pimpl-idiom c++11

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

如何避免由于编译器错误而导致无法访问的代码警告?

对于VS2015更新2,减少的可重现测试用例如下.我们试图建立"警告级别4",我们将警告视为致命错误,以提高注意到警告的可能性.我希望社区中的某个人已经遇到过这种情况并找到了合理的解决方法.

如果没有其他人看到过相同的问题,这可能会被证明过于局部化,所以我想指出的是,"人们应该多么严重地破坏代码库以逃避糟糕的编译器警告",或者等效地说,"应该怎么做?向缺少错误报告的编译器供应商报告错误".

#ifdef _WIN32
#pragma warning( push )
#pragma warning( disable : 4702 ) // As suggested by comments
#endif
template <class Type>
void func (Type t)
{
    t.func ();
    t.func ();
}
#ifdef _WIN32
#pragma warning( pop )
#endif

struct NoThrow
{
    void func () {}
};

struct Throws
{
    void func () {throw 1;}
};

int main ()
{
    NoThrow nt;
    func (nt);

    Throws t;
    func (t);
}
Run Code Online (Sandbox Code Playgroud)

这会触发无法访问的代码警告.模板化函数本身看起来很合理,但对于一个特定的实例化,编译器能够确定第二个t.func()已死,因此它会警告无法访问的代码.

对于VS2015来说,这似乎是一个相当明确的实施问题,所以我们在这里打开了一个错误报告.

我们收到了微软的一些指导,

不幸的是,编译器的后端(此警告源自此处)没有模板函数实例化的真实概念作为单个模板函数的实例.它们都只是具有非常相似的名字的函数,如果它曾经打算将(装饰的)名称与彼此进行比较.它永远不会.所以它在这里看到的是一个函数,它有一些无法访问的代码,它警告它,另一个函数没有无法访问的代码,它没有.您提出的这种"交叉功能警告"的概念,我们在不同的模板实例中收集和比较数据,并且仅在纯LTCG二进制文件的情况下警告这个或那个是非常困难的,否则是不可能的.

考虑标题foo.h中的模板Foo.假设a.cpp包含它并创建具有无法访问代码的Foo,然后b.cpp包含它并创建没有无法访问代码的Foo.你建议在a.cpp中Foo不应该警告,调用无法访问的代码,因为Foo存在没有无法访问的代码.但是,Foo是在不同的文件中,在不同的进程中,在不同的cl.exe调用中编译的,并且在将来最不方便.很明显,编译器没有能力将未来的过程扩展到未出生的过程并提取计算是否需要警告的信息.

我们这里唯一真正可行的选择是关闭所有模板的无法访问的代码警告,我会诚实地说,直到我们确定所造成的伤害大于所做的好处时才会发生(这是一个净坏).警告有误报,它会发生.我会尝试考虑其他选项,并查看行号/文件.

上面的链接可能不可用,但随着互联网附带缓存,您可以在此处 …

c++ visual-studio-2015

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

在不同范围的结构之间进行转换

我有兴趣在指向可能兼容的结构的指针之间进行转换.他们将使用相同的标签,相同的成员使用相同的顺序.虽然目标代码库被编译为C或C++,但为了简化这个问题,我想将其限制为仅限C++.

在这种情况下,我确信编译器的行为会合理,但我找不到支持证据表明它需要这样做.

激励代码的例子是:

#include <cstdio>

void foo(void * arg)
{
    struct example
    {
        int a;
        const char * b;
    };

    example * myarg = static_cast<example *>(arg);
    printf("meaning of %s is %d\n",myarg->b,myarg->a);
}

void bar(void)
{
    struct example
    {
        int a;
        const char * b;
    };

    example on_stack {42, "life"};
    foo(&on_stack);
}

int main(int,char**)
{
    bar();
}
Run Code Online (Sandbox Code Playgroud)

我对C++ 11标准的运气不太好.关于类的第9节建议示例将是"布局兼容的",这听起来令人鼓舞,但我无法找到结构"布局兼容"的后果的描述.特别是,我可以将一个指针指向另一个指针而不会产生后果吗?

一位同事认为"布局兼容"意味着memcpy将按预期工作.鉴于所讨论的结构也总是易于复制,以下名义上效率低下的代码可能会避免UB:

#include <cstdio>
#include <cstring>

void foo(void * arg)
{
    struct example
    {
        int a;
        const char * b;
    };

    example local; …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer

12
推荐指数
2
解决办法
784
查看次数

相当于LLVM IR的#include

我发现自己有很多有用的函数和常量用LLVM的IR编写.我可以通过将它与手写IR结合使用这个伪库,前提是手写的IR以可能冗长的声明列表开头.我知道IR不一定被设计为通用编程语言来编写内容.

这就像在一个文件中编写大量C函数,然后在任何使用它们的地方重新声明它们.在C中,这可以使用#include和头文件.这并不完美,但它反复写出原型.

什么是在IR中实现类似的最不讨厌的方式?它只需要一遍又一遍地打败这些东西(我目前以复制和粘贴的方式做)并使用cat作为自定义构建步骤.

谢谢!

llvm llvm-ir

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

写函数原型的明智方法

我正在寻找一种(干净的)编写函数定义和函数原型的方法,而不需要代码重复.由于DRY是一个好主意,并且头文件中的手动编码原型是一个明显的违规,这似乎是一个合理的要求.

下面的示例代码表示使用预处理器解决问题的(粗略)方法.它似乎不太可能是最佳的,但似乎确实可以正常工作.

使用单独的文件和复制:

foo.h:
#ifndef FOO_H
  #define FOO_H
  // Normal header file stuff
  int dofoo(int a);
#endif /* FOO_H */

foo.c:
#include "foo.h"
int dofoo(int a) {
  return a * 2;
}
Run Code Online (Sandbox Code Playgroud)

使用C预处理器:

foo.h:
#ifndef FOO_H
  #define FOO_H

  // Normal header file stuff

  #ifdef PROTOTYPE // if incorrect:
  // No consequences for this test case, but we lose a sanity check
    #error "PROTOTYPE set elsewhere, include mechanism will fall over"
  #endif

  #define PROTOTYPE // if incorrect:
  // "error: redefinition of …
Run Code Online (Sandbox Code Playgroud)

c dry

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

非成员函数模板什么时候有内部链接?

C++11 草案,14.0.4:

非成员函数模板可以有内部链接;任何其他模板名称应具有外部链接。

此查询是分离模板声明和定义的结果。例如,我们可以在头文件中写入以下内容。

template <typename T>
bool operator==(T const & l, T const & r);
Run Code Online (Sandbox Code Playgroud)

在注定要成为单个翻译单元的单个源文件中,我们编写定义。我们还在同一个翻译单元中为 type 隐式或显式实例化它foo

template <typename T>
bool operator==(T const & l, T const & r)
{
  return extract(l) == extract(r); // extract is uninteresting
}
Run Code Online (Sandbox Code Playgroud)

在第二个翻译单元中,它只能从头部看到定义,我们尝试使用foo{} == foo{},即调用在operator==别处实例化的 。

目前,这“有效”。链接器按照我的希望修补了两个翻译单元。

但是,如果功能模板具有内部链接,则链接可能会失败。例如,我们可以通过在匿名命名空间中实例化来强制执行此操作。

规范中的“can”是否表示源代码控制链接(例如 by namespace {})或允许编译器选择实例化是具有内部链接还是外部链接?

我不相信这里有任何未定义的行为,但我正在努力说服自己选择的链接不是实现细节。如果该符号已在至少一个 TU 中的上下文中实例化,表明它将是外部的,我是否可以依赖其他翻译单元可见的符号?

编辑:DR1603(感谢 Eugene Zavidovsky!)包含一个建议,以完全删除上面引用的句子,以及链接规则的一般合理化。

c++ templates language-lawyer c++11

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

使用枚举基因编写枚举时会出现模糊的重载,但只能使用clang

我想使用operator <<来编写具有指定基类型的枚举.令我惊讶的是,似乎我必须自己写出操作员.例如,我想写的代码是

#include <iostream>
enum myenum : uint16_t
{
    X = 0,
};
int main ()
{
    std::cout << "Value is" << X << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

gcc 4.8和visual studio 2015对此没有任何问题.clang ++ - 3.6错误

# clang++-3.6 -std=c++11 -O0 ostream.cpp -o test.exe
ostream.cpp:18:29: error: use of overloaded operator '<<' is ambiguous (with operand types
      'basic_ostream<char, std::char_traits<char> >' and 'myenum')
    std::cout << "Value is" << X << std::endl;
    ~~~~~~~~~~~~~~~~~~~~~~~ ^  ~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:181:7: note: 
      candidate function
      operator<<(unsigned short __n)
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:189:7: note: …
Run Code Online (Sandbox Code Playgroud)

c++ c++11 clang++

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

Clojure的优化工作如何工作,它在哪里?

我是Clojure的新手,但不是lisp.一些设计决策对我来说很奇怪 - 特别是需要一个向量用于函数参数并使用recur显式请求尾调用.

将列表转换为向量(反之亦然)是优化器的标准操作.通过在编译为字节代码之前重写为等效的clojure,可以将尾调用转换为迭代.[]和recur语法表明当前实现中都没有这些优化.

我想在什么地方在执行我能找到的任何/所有源到源变换通行证.我不会说Java很好,所以我很难在代码库中导航.

如果在逐个函数转换为JVM的字节代码之前没有任何优化,我会对此的设计原理感兴趣.也许是为了实现更快的编译?

谢谢.

clojure compiler-optimization

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

将 .git 移动到与它管理的源不同的目录中

我不是在问如何移动 git 存储库。我想将 .git 中包含的元数据移动到一台机器上的其他地方,而不影响世界其他地方。

目标是拥有

~/gitmetadata/myproject/.git
~/gitmetadata/myproject/.gitignore
~/somecode/myproject/ # No .git here anymore
Run Code Online (Sandbox Code Playgroud)

本练习的目的是将 .git 放在持久性存储 (ssd) 上,而保存源代码/目标代码等的工作目录在 ram 磁盘上。我并不特别想将 .git 也放在 ramdisk 上,因为我不想通过克隆远程存储库来启动每次重新启动。

理想情况下,我正在寻找一个配置选项,我可以将其写入每台机器的配置文件,上面写着“实际上,文件在那里”。

我可以通过拥有一个我从中提取的本地存储库来解决这个问题,前提是我学习了如何配置一个 git 存储库来进行透明转发,或者通过修改文件系统 unionfs 样式来解决这个问题,这会很慢。

git 可以将 .git 元数据放在其他地方吗?

编辑:答案之一包括短语“git config core.worktree”。将此输入谷歌发现了我的搜索没有的重复项,2013 年2009 年

git

3
推荐指数
2
解决办法
266
查看次数

对象是否完全构建在初始化列表的末尾?

这是在构造函数中调用复制构造函数的衍生产品.

我相信一个对象是完全形成的,并且可以预期在初始化列表的末尾表现如此(编辑:我错了!).具体来说,成员函数和从构造函数本身访问本地状态的行为与其他任何成员函数完全相同.

这似乎是一个有点争议的观点,但另一种选择是,只有构造函数正常返回后才能完全形成对象.

以下是一个快速和脏的测试用例,它显示初始化初始化列表中提到的所有成员字段以及未获取默认构造的成员字段.

#include <cstdio>

struct noise
{
  noise() { printf("noise default constructed\n"); }
  noise(int x) { printf("noise integer constructed %u\n", x); }
  ~noise() { printf("noise dtor\n"); }
};

struct invoke : public noise
{
  noise init;
  noise body;
  invoke() : noise(3), init(4)
  {
    body = noise(5);
    throw *this; // try to use the object before returning normally
  }
  ~invoke() { printf("invoke dtor\n"); }
};

int main()
{
  try
    {
      invoke i;
    }
  catch (...)
    {
    } …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer

3
推荐指数
2
解决办法
187
查看次数