因为std::function是可复制的,所以标准要求用于构造它的callables也是可复制的:
n337(20.8.11.2.1)
template<class F> function(F f);要求:
F应为CopyConstructible.f对于参数类型ArgTypes和返回类型,应为Callable(20.8.11.2)R.A的拷贝构造函数和析构函数不会抛出异常
这意味着不可能std::function从不可复制的绑定对象或捕获仅移动类型的lambda形成std::unique_ptr.
似乎可以为仅移动的callables实现这样一个仅移动的包装器.是否存在标准库仅限移动等效std::function或者,是否存在针对此问题的常见解决方法?
前几天有人曾问过为什么有些东西会与clang编译,而不是与gcc编译.我直观地理解了发生了什么,并且能够帮助这个人,但它让我想知道 - 根据标准,哪个编译器是正确的?这是代码的简化版本:
#include <iostream>
#include <string>
class foo
{
public:
foo(const std::string& x):
name(x)
{ }
foo& operator()(const std::string& x)
{
std::cout << name << ": " << x << std::endl;
return (*this);
}
std::string name;
};
int main()
{
std::string x = "foo";
foo(x)("bar")("baz");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用clang ++可以很好地编译,但是g ++会出现以下错误:
runme.cpp: In function ‘int main()’:
runme.cpp:21:11: error: conflicting declaration ‘foo x’
foo(x)("bar")("baz");
^
runme.cpp:20:17: error: ‘x’ has a previous declaration as ‘std::string x’
std::string x = …Run Code Online (Sandbox Code Playgroud) 想象一下以下简化代码:
#include <iostream>
void foo(const int& x) { do_something_with(x); }
int main() { foo(42); return 0; }
Run Code Online (Sandbox Code Playgroud)
(1)除了优化之外,42传递给什么时会发生什么foo?
编译器是否在某处(在堆栈上?)并将其地址传递给foo?
(1a)标准中是否有任何内容规定在这种情况下要做什么(或者它是否严格取决于编译器)?
现在,想象一下略有不同的代码
#include <iostream>
void foo(const int& x) { do_something_with(x); }
struct bar { static constexpr int baz = 42; };
int main() { foo(bar::baz); return 0; }
Run Code Online (Sandbox Code Playgroud)
它不会链接,除非我定义int bar::baz;(由于ODR?).
(2)除了ODR之外,为什么编译器不能对上面的42做什么呢?
简化事物的一种明显方法是定义foo为:
void foo(int x) { do_something_with(x); }
Run Code Online (Sandbox Code Playgroud)
但是,如果是模板,会怎么做?例如:
template<typename T>
void foo(T&& x) { do_something_with(std::forward<T>(x)); }
Run Code Online (Sandbox Code Playgroud)
(3)是否有一种优雅的方式来foo表示接受x原始类型的价值?或者我是否需要专注于SFINAE或其他一些?
编辑 …
c++ one-definition-rule c++11 pass-by-const-reference forwarding-reference
让我们std::unique_lock从标准库中实现:
struct defer_lock_t { explicit defer_lock_t() = default; };
struct try_to_lock_t { explicit try_to_lock_t() = default; };
struct adopt_lock_t { explicit adopt_lock_t() = default; };
inline constexpr defer_lock_t defer_lock {};
inline constexpr try_to_lock_t try_to_lock {};
inline constexpr adopt_lock_t adopt_lock {};
unique_lock (mutex_type& m, defer_lock_t t) noexcept;
unique_lock (mutex_type& m, try_to_lock_t t);
unique_lock (mutex_type& m, adopt_lock_t t);
Run Code Online (Sandbox Code Playgroud)
是否有人不会/不能/不应该使用枚举而不是结构来实现标签调度?如:
enum defer_lock_t { defer_lock };
enum try_to_lock_t { try_to_lock };
enum adopt_lock_t { adopt_lock };
unique_lock (mutex_type& m, defer_lock_t t) noexcept; …Run Code Online (Sandbox Code Playgroud) 特定 enum class val { foo = 1, bar = 2, baz = 4 };
可以定义:
val operator|(val x, val y)
{
return static_cast<val>(static_cast<int>(x) | static_cast<int>(y));
}
Run Code Online (Sandbox Code Playgroud)
但是,这样做在语义上是否正确?
我倾向于不,如下所示,看似表现良好的例子:
int convert(val x)
{
switch(x)
{
case val::foo: return 42;
case val::bar: return 53;
case val::baz: return 64;
}
}
Run Code Online (Sandbox Code Playgroud)
使用g ++和clang ++编译时,调用convert(val::foo | val::bar)将返回0.
我的问题是双重的:
1.a在上面链接的例子中,哪个编译器是正确的,g ++或clang ++?
我可以想到几种可能的实现:
enum class val { foo, bar, baz, size …Run Code Online (Sandbox Code Playgroud) 这是非常基本的代码:
#include <memory>
class foo
{
public:
~foo() noexcept(false) { }
};
int main()
{
auto x = std::make_shared<foo>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译如下:
g++ -std=c++11 test.cpp <-- OK
clang++ -std=c++11 test.cpp <-- OK
clang++ -std=c++11 -stdlib=libc++ test.cpp <-- FAIL
Run Code Online (Sandbox Code Playgroud)
使用libc ++编译时,它会失败:
/usr/bin/../include/c++/v1/memory:3793:7: error: exception specification of overriding function is more lax than base version
class __shared_ptr_emplace
^
/usr/bin/../include/c++/v1/memory:4423:26: note: in instantiation of template class 'std::__1::__shared_ptr_emplace<foo,
std::__1::allocator<foo> >' requested here
::new(__hold2.get()) _CntrlBlk(__a2, _VSTD::forward<_Args>(__args)...);
^
/usr/bin/../include/c++/v1/memory:4787:29: note: in instantiation of function template …Run Code Online (Sandbox Code Playgroud) auto numbers = {1, 2, 3, 4}; // 'numbers' is an std::intializer_list<int>
auto num_array[] = {1, 2, 3, 4} // error -> declared as an array of 'auto'
Run Code Online (Sandbox Code Playgroud)
为什么会出现这种限制?
编辑:考虑以下两个例子:
std::string x;
{
std::string y = "extremely long text ...";
...
x = y; // *** (1)
}
do_something_with(x);
Run Code Online (Sandbox Code Playgroud)
struct Y
{
Y();
Y(const Y&);
Y(Y&&);
... // many "heavy" members
};
struct X
{
X(Y y) : y_(std::move(y)) { }
Y y_;
}
X foo()
{
Y y;
...
return y; // *** (2)
}
Run Code Online (Sandbox Code Playgroud)
y在线(1)和(2)的两个例子中,它的寿命接近结束并且即将被破坏.很明显,它可以被视为右值并在两种情况下都可以移动.在(1)中,它的内容可以移入x和移入(2)到temp的实例中X().y_.
我的问题是:
1)是否会在上述任何一个示例中移动?(a)如果是,则采用何种标准规定.(b)如果不是,为什么不呢?这是标准中的遗漏还是我没有想到的另一个原因?
2)如果上述答案为否.在第一个例子中,我可以改变(1)x = std::move(y)以强制编译器执行移动.在第二个示例中,我可以做什么来向编译器指示y可以移动?return std::move(y)?
注意:我故意返回(2)中的实例Y而不是X …
这是一个简单的示例程序:
using fn_string = function<void(const string&)>;
using fn_optional_string = function<void(const optional<string>&)>;
void foo(fn_string) { cout << "string" << endl; }
void foo(fn_optional_string) { cout << "optional string" << endl; }
int main()
{
foo([&](const string&){ });
foo([&](const optional<string>&){ }); // <-- ambiguous
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它有2个重载foo()- 一个带string参数函数,另一个带函数optional<string>.
为什么第二次呼叫foo()模棱两可?
有没有一种简单的方法来解决它?没有演员阵容?
UPDATE
以上是我试图解决的以下现实世界问题的过度简化示例,即:
using delegate = variant<
function<void()>,
function<void(const string&)>,
function<void(const optional<string>&)>
>;
struct foo
{
void add_delegate(delegate fn) { fns.push_back(std::move(fn)); }
vector<delegate> fns; …Run Code Online (Sandbox Code Playgroud) 因此,我在窗口应用程序中使用 D3D。
我使用以下参数启动了 D3D:
windowed: true;
backbufferformat: D3DFMT_X8R8G8B8;
presentinterval: D3DPRESENT_INTERVAL_ONE;
swapeffect: DISCARD
Run Code Online (Sandbox Code Playgroud)
每次调用 OnPaint 时,我都会将图像渲染到后缓冲区并将其呈现到前面。
据我所知(MSDN也是这么说的),一旦我设置了D3DPRESENT_INTERVAL_ONE,vsync就会起作用。
但在这种情况下,水平拖动时图像会撕裂。
(图像上似乎有一条线,线下方的图像显示在监视器上,上面的部分如下。)
一些网站说 D3DPRESENT_INTERVAL_ONE 在窗口应用程序中不起作用。
我怎样才能启用垂直同步?
ps我终于发现D3D垂直同步是启用的,而有些窗口设置不正确,也许窗口本身没有同步。不过,我还没有看过设置。