今天,我发现了一个相当有趣的事情g++或者nm......构造函数定义似乎在库中有两个条目.
我有一个标题thing.hpp:
class Thing
{
Thing();
Thing(int x);
void foo();
};
Run Code Online (Sandbox Code Playgroud)
而且thing.cpp:
#include "thing.hpp"
Thing::Thing()
{ }
Thing::Thing(int x)
{ }
void Thing::foo()
{ }
Run Code Online (Sandbox Code Playgroud)
我编译它:
g++ thing.cpp -c -o libthing.a
Run Code Online (Sandbox Code Playgroud)
然后,我继续nm:
%> nm -gC libthing.a
0000000000000030 T Thing::foo()
0000000000000022 T Thing::Thing(int)
000000000000000a T Thing::Thing()
0000000000000014 T Thing::Thing(int)
0000000000000000 T Thing::Thing()
U __gxx_personality_v0
Run Code Online (Sandbox Code Playgroud)
如您所见,两个构造函数Thing都在生成的静态库中列出了两个条目.我的g++是4.4.3,但是同样的行为发生在clang,所以这不仅仅是一个gcc问题.
这不会引起任何明显的问题,但我想知道:
编辑:对于卡尔,没有C参数的输出:
%> …Run Code Online (Sandbox Code Playgroud) 我在使用C++类型特征时遇到了一些奇怪的行为,并将我的问题缩小到这个古怪的小问题,我将给出大量的解释,因为我不想留下任何误解的东西.
假设您有这样的程序:
#include <iostream>
#include <cstdint>
template <typename T>
bool is_int64() { return false; }
template <>
bool is_int64<int64_t>() { return true; }
int main()
{
std::cout << "int:\t" << is_int64<int>() << std::endl;
std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
std::cout << "long int:\t" << is_int64<long int>() << std::endl;
std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在使用GCC(以及32位和64位MSVC)进行32位编译时,程序的输出将为:
int: 0
int64_t: 1
long int: 0
long long int: 1
Run Code Online (Sandbox Code Playgroud)
但是,由64位GCC编译产生的程序将输出:
int: 0
int64_t: 1 …Run Code Online (Sandbox Code Playgroud) 我经常使用一种技术,我称之为"懒人enable_if",我使用它decltype和逗号运算符来启用基于某些模板输入的函数.这是一个小例子:
template <typename F>
auto foo(F&& f) -> decltype(f(0), void())
{
std::cout << "1" << std::endl;
}
template <typename F>
auto foo(F&& f) -> decltype(f(0, 1), void())
{
std::cout << "2" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
随着--std=c++11,g ++ 4.7+和Clang 3.5+愉快地编译那段代码(并且它按照我的预期工作).但是,当使用MSVC 14 CTP5时,我得到这个错误抱怨foo已经定义:
错误错误C2995:'unknown-type foo(F &&)':函数模板已经定义了c ++ - scratch main.cpp 15
所以我的问题是:"懒人enable_if"是合法的C++还是这是一个MSVC错误?
我正在编译以下简单程序g++-4.6.1 --std=c++0x:
#include <algorithm>
struct S
{
static constexpr int X = 10;
};
int main()
{
return std::min(S::X, 0);
};
Run Code Online (Sandbox Code Playgroud)
我收到以下链接器错误:
/tmp/ccBj7UBt.o: In function `main':
scratch.cpp:(.text+0x17): undefined reference to `S::X'
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
我意识到内联定义的静态成员没有定义符号,但我在(可能是有缺陷的)印象中使用constexpr告诉编译器始终将符号视为表达式; 所以,编译器会知道传递对符号的引用是不合法的S::X(出于同样的原因,你不能引用文字10).
但是如果S被声明为命名空间,即"命名空间S"而不是"struct S",那么一切都很好.
这是一个g++错误还是我仍然需要使用技巧来解决这个烦恼?
我有相当数量的代码,它依赖于捕获shared_from_this()当使用lambda表达式作为回调时确保我的实例保持活动状态:
std::shared_ptr<Thing> self = shared_from_this();
auto doSomething = [this, self] ()
{
// various statements, none of which reference self, but do use this
}
Run Code Online (Sandbox Code Playgroud)
所以问题是:由于我没有self在lambda体内引用,是否允许一致的编译器优化捕获?
考虑以下程序:
#include <functional>
#include <iostream>
#include <memory>
std::function<void ()> gFunc;
struct S : std::enable_shared_from_this<S>
{
void putGlobal()
{
auto self = shared_from_this();
gFunc = [self] { };
}
};
int main()
{
auto x = std::make_shared<S>();
std::cout << x.use_count() << std::endl;
x->putGlobal();
std::cout << x.use_count() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
1 …Run Code Online (Sandbox Code Playgroud) 通过Clang-Format样式选项进行搜索,我似乎无法找到控制C++属性放置行为的方法.
举一个例子,取这两个声明,第一个不会溢出列限制,第二个声明:
template <typename TChar>
[[gnu::always_inline]]
static ptr<TChar> within_limit(ptr<TChar> first, ptr<TChar> last);
template <typename TChar, typename FApply, typename... FApplyRest>
[[gnu::always_inline]]
static ptr<TChar> overflow(ptr<TChar> first, ptr<TChar> last, const FApply& apply, const FApplyRest&... apply_rest);
Run Code Online (Sandbox Code Playgroud)
无论我如何调整我.clang-format,输出都是这个的一些变体:
[[gnu::always_inline]] static ptr<TChar> within_limit(ptr<TChar> first, ptr<TChar> last);
[[gnu::always_inline]] static ptr<TChar>
overflow(ptr<TChar> first, ptr<TChar> last, const FApply& apply, const FApplyRest&... apply_rest);
Run Code Online (Sandbox Code Playgroud)
将属性与类型放在同一行是相当难以理解的(对我而言),所以我不希望clang-format这样做.使用__attribute__((always_inline))展品的行为相同.在单个列表中指定多个属性([[noreturn, gnu::cold]])会导致重新格式化([[ noreturn, gnu::cold ]]由于我不清楚的原因).格式化程序至少对属性有一些基本的了解.
SO:有没有办法让clang-format属性放在自己的行上(C++相当于BreakAfterJavaFieldAnnotations)?
尝试过的变通方法
使用// clang-format …
如何@interface在Scala中创建一个?我老实地觉得这个问题很愚蠢,但我无法在任何地方找到这种语法.我知道你可以使用它们,但是你如何在Scala中实际定义新的呢?
Java的:
public @interface MyAnnotation { }
Run Code Online (Sandbox Code Playgroud)
斯卡拉:
???
Run Code Online (Sandbox Code Playgroud) 我总是将我的.NET程序集标记为COM可见[assembly: ComVisible(true)],以为我从来不知道有人可能需要从COM调用它们.我也开始使用FxCop并开始从代码分析中看到这个警告:
CA1017:Microsoft.Design:因为"MyLibrary.dll"公开了外部可见类型,所以在程序集级别使用ComVisible(false)标记它,然后使用ComVisible标记应该向COM客户端公开的程序集中的所有类型(true)
是否有一些理由让您不希望所有公共类型都暴露给COM?我猜这有,但我无法想象这是什么原因.如果有的话,它似乎非常不方便.
考虑以下程序:
#include <type_traits>
struct Thrower
{
~Thrower() noexcept(false) { throw 1; }
};
struct Implicit
{
Thrower t;
};
static_assert(!std::is_nothrow_destructible<Implicit>::value, "Implicit");
struct Explicit
{
~Explicit() {}
Thrower t;
};
static_assert(!std::is_nothrow_destructible<Explicit>::value, "Explicit");
Run Code Online (Sandbox Code Playgroud)
有g++-4.8.1,静态断言失败Explicit- 它似乎认为~Explicit()是noexcept.这与我的期望不符.根据§12.4.3:
没有异常规范的析构函数的声明被隐式地认为具有与隐式声明相同的异常规范
这里有趣的是Implicit根据我对§15.4.14(通过§12.4.7)的解释,检查似乎表现得很好.
...如果f是...析构函数...它是隐式异常 - 规范指定...
noexcept(true)如果它直接调用的每个函数都不允许例外,则f具有异常规范.
g++-4.7缺乏is_nothrow_destructable,我写了自己检查4.7中的行为.该程序似乎编译得非常好.我保留完全错误的权利和我的困惑的来源:
template <typename T>
struct is_nothrow_destructible
{
static constexpr bool value = noexcept(std::declval<T>().~T());
};
Run Code Online (Sandbox Code Playgroud)
TL; DR:为什么g++-4.8.1认为没有异常规范的显式声明的析构函数总是如此 noexcept(true)?
更新:我在此打开了一个错误:57645 …
我需要使用offsetof从template一个成员选择.如果您原谅尴尬的语法,我想出办法:
template <typename T,
typename R,
R T::*M
>
constexpr std::size_t offset_of()
{
return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
Run Code Online (Sandbox Code Playgroud)
用法并不完美(最好烦恼):
struct S
{
int x;
int y;
};
static_assert(offset_of<S, int, &S::x>() == 0, "");
static_assert(offset_of<S, int, &S::y>() == sizeof(int), "");
Run Code Online (Sandbox Code Playgroud)
非constexpr形式更容易使用:
template <typename T, typename R>
std::size_t offset_of(R T::*M)
{
return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
Run Code Online (Sandbox Code Playgroud)
明显的缺点是它不是在编译时完成的(但更容易使用):
int main()
{
std::cout << offset_of(&S::x) << std::endl;
std::cout << offset_of(&S::y) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找的是语法像非constexpr品种,但仍然完全编译时间; 但是,我无法想出它的语法.我也很满意offset_of<&S::x>::value(就像其他类型特征一样),但无法弄清楚它的语法魔法.
c++ ×7
c++11 ×5
gcc ×2
.net ×1
annotations ×1
clang-format ×1
com ×1
constexpr ×1
constructor ×1
cstdint ×1
lambda ×1
linker ×1
noexcept ×1
offsetof ×1
scala ×1
sfinae ×1
type-traits ×1
visual-c++ ×1