std::get 似乎不是SFINAE友好的,如下面的测试用例所示:
template <class T, class C>
auto foo(C &c) -> decltype(std::get<T>(c)) {
return std::get<T>(c);
}
template <class>
void foo(...) { }
int main() {
std::tuple<int> tuple{42};
foo<int>(tuple); // Works fine
foo<double>(tuple); // Crashes and burns
}
Run Code Online (Sandbox Code Playgroud)
目标是将第二次呼叫foo转向第二次超载.在实践中,libstdc ++给出:
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.0/../../../../include/c++/6.3.0/tuple:1290:14: fatal error: no matching function for call to '__get_helper2'
{ return std::__get_helper2<_Tp>(__t); }
^~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
libc ++更直接,直接static_assert引爆:
/usr/include/c++/v1/tuple:801:5: fatal error: static_assert failed "type not found in type list"
static_assert ( value != -1, "type not found …Run Code Online (Sandbox Code Playgroud) 这有两件事可行.我们可以实例化一个转发函数模板来获取一个带左值的函数指针:
template <class T>
void f(T &&) {}
void(*p)(int &) = f; // Cool!
Run Code Online (Sandbox Code Playgroud)
我们还可以将带有左值的非捕获通用lambda转换为带左值的函数指针:
auto l = [](auto &) { };
void (*lp)(int &) = l; // Still cool!
Run Code Online (Sandbox Code Playgroud)
但显然GCC和Clang都没有将转发通用lambda转换为带左值的函数指针:
auto l = [](auto &&) { };
void (*lp)(int &) = l; // Not cool!
Run Code Online (Sandbox Code Playgroud)
GCC产出:
<source>:9:21: error: invalid user-defined conversion from '<lambda(auto:1&&)>' to 'void (*)(int&)' [-fpermissive]
void (*lp)(int &) = l;
^
Run Code Online (Sandbox Code Playgroud)
Clang输出:
<source>:9:8: fatal error: no viable conversion from '(lambda at <source>:7:10)' to 'void (*)(int &)'
void …Run Code Online (Sandbox Code Playgroud) c++ templates function-pointers language-lawyer generic-lambda
对于典型的编程需求,C++ 11是一个伟大的里程碑 - 我们用标准库替换了95%的Boost代码.
然而,标准库中尚未涵盖的库的当前状态是什么?
由于需要Signals2和Lockfree,我开始想知道.
我最近遇到了将指针指向成员应用于迭代器指定的对象的需要.我尝试过自然语法:
ite->*ptr = 42;
Run Code Online (Sandbox Code Playgroud)
令我沮丧的是,它没有编译.迭代器不会过载operator->*,但更令人惊讶的是智能指针也不会.我需要诉诸以下笨拙:
(*ite).*ptr = 42;
Run Code Online (Sandbox Code Playgroud)
试验(参见下面的实例)已经表明,对于自定义类,对于指向成员的指针和指向成员函数的指针,这样的语法似乎是可以实现的,至少从C++ 14开始.
因此:
operator->*,还是仅仅是一种疏忽?operator->*在定义类似指针的类时,我应该重载,还是同样的理由适用于我?实例 - 什么是编译,什么不编译,以及自定义类的概念验证.
请考虑以下代码段:
#include <iostream>
int main() {
std::string foo;
foo = -1; // why is the compiler not complaining about this?
std::cout << "1" << std::endl;
std::cout << foo << std::endl;
std::cout << "2" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
实际输出(ideone.com C++ 14模式和GCC 4.8.4):
<no output>
问题:
foo = -1,我得到了正确的标准输出(1和2).编译器编译的是什么foo = -1;导致后续的couts失败?当心,我们正在绕过龙的巢穴.
考虑以下两个类:
struct Base {
std::string const *str;
};
struct Foo : Base {
Foo() { std::cout << *str << "\n"; }
};
Run Code Online (Sandbox Code Playgroud)
如您所见,我正在访问未初始化的指针.还是我?
让我们假设我只使用Base那些微不足道的类,只不过是(可能是嵌套的)指针.
static_assert(std::is_trivial<Base>{}, "!");
Run Code Online (Sandbox Code Playgroud)
我想Foo分三步构建:
为a分配原始存储空间 Foo
Base通过placement-new 初始化一个适当放置的子对象
Foo通过placement-new 构建.
我的实现如下:
std::unique_ptr<Foo> makeFooWithBase(std::string const &str) {
static_assert(std::is_trivial<Base>{}, "!");
// (1)
auto storage = std::make_unique<
std::aligned_storage_t<sizeof(Foo), alignof(Foo)>
>();
Foo * const object = reinterpret_cast<Foo *>(storage.get());
Base * const base = object;
// (2)
new (base) Base{&str};
// (3)
new …Run Code Online (Sandbox Code Playgroud) 考虑
struct base {};
struct child : base {};
Run Code Online (Sandbox Code Playgroud)
众所周知,sizeof(child)通过应用空基优化可以是1 .
但是现在考虑一下
struct base {};
struct child : base {base b;};
Run Code Online (Sandbox Code Playgroud)
编译器现在可以应用空基优化,还是必须sizeof(child)至少为2?
假设您需要从函数中知道是否已将此函数作为静态对象初始化的一部分进行调用.是否有标准或特定于平台的方法?
我深入研究了许多应用程序使用的DLL的源代码.这个DLL暴露了一个Init函数,这个函数应该构造一个boost::asio::deadline_timer稍后使用的函数(但是DLL可以在没有降级模式的情况下工作).
问题是在静态对象初始化期间(DLL加载时间)不能构造定时器,以免其构造函数死锁.
当然,每个人和他们的猫Init来自世界各地(是的,多次!),包括来自源代码的静态构造函数我不会编辑,因此需要检测那种情况并挽救.
在实用主义克服了厌恶之后,我最终走上了callstack试图找到wWinMain并推断出静态初始化结束了.这很糟糕,并且不适用于动态加载的二进制文件,幸好这不在我的特定情况范围内.我当然希望有一种更清洁的方式.
我正在考虑使用"自杀对象"来模拟游戏中的实体,即能够自行删除的对象.现在,一般的C++ 03的实现(普通旧delete this)不执行任何潜在指的自杀的对象,这就是为什么我使用的其他对象std::shared_ptr和std::weak_ptr.
现在进行代码转储:
#include <memory>
#include <iostream>
#include <cassert>
struct SuObj {
SuObj() { std::cout << __func__ << '\n'; }
~SuObj() { std::cout << __func__ << '\n'; }
void die() {
ptr.reset();
}
static std::weak_ptr<SuObj> create() {
std::shared_ptr<SuObj> obj = std::make_shared<SuObj>();
return (obj->ptr = std::move(obj));
}
private:
std::shared_ptr<SuObj> ptr;
};
int main() {
std::weak_ptr<SuObj> obj = SuObj::create();
assert(!obj.expired());
std::cout << "Still alive\n";
obj.lock()->die();
assert(obj.expired());
std::cout << "Deleted\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此代码似乎工作正常.但是,我想让别人去关注它.这段代码有意义吗?我是否盲目地驶入未定义的土地?我应该放弃键盘并立即开始艺术研究吗?
我希望这个问题能够充分缩小.看起来有点微小而且低级别的CR. …
我正在尝试bar在另一个函数的参数(foo1/ foo2)的上下文中解析重载函数()的地址.
struct Baz {};
int bar() { return 0; }
float bar(int) { return 0.0f; }
void bar(Baz *) {}
void foo1(void (&)(Baz *)) {}
template <class T, class D>
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
int main() {
foo1(bar); // Works
foo2<Baz>(bar); // Fails
}
Run Code Online (Sandbox Code Playgroud)
没有问题foo1,bar明确指定了类型.
但是,foo2除了一个版本之外,通过SFINAE禁用自身bar,无法使用以下消息进行编译:
main.cpp:19:5: fatal error: no matching function for call to 'foo2'
foo2<Baz>(bar); // Fails
^~~~~~~~~
main.cpp:15:6: note: candidate template …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++14 ×2
c++17 ×2
sfinae ×2
boost ×1
gcc ×1
iterator ×1
overloading ×1
ownership ×1
shared-ptr ×1
stdtuple ×1
stl ×1
template-argument-deduction ×1
templates ×1