我正在更新当前使用自定义等效std::variant于C++ 17 的代码库.
在代码的某些部分中,变量是从已知的替代方法重置的,因此该类提供了一个断言index()当前值的方法,但仍然无条件地直接调用正确的析构函数.
这用于一些紧密的内环,并且具有(测量的)非平凡的性能影响.这是因为当有问题的替代方案是一个简单的可破坏类型时,它允许编译器消除整个破坏.
从表面上看,在我看来,我无法std::variant<>通过STL中的当前实现实现这一点,但我希望我错了.
有没有办法实现这一点,我没有看到,或者我运气不好?
编辑:根据要求,这是一个用法示例(使用@ TC的示例作为基础):
struct S {
~S();
};
using var = MyVariant<S, int, double>;
void change_int_to_double(var& v){
v.reset_from<1>(0.0);
}
Run Code Online (Sandbox Code Playgroud)
change_int_to_double 有效编译:
@change_int_to_double(MyVariant<S, int, double>&)
mov qword ptr [rdi], 0 // Sets the storage to double(0.0)
mov dword ptr [rdi + 8], 2 // Sets the index to 2
Run Code Online (Sandbox Code Playgroud)
编辑#2
感谢来自@TC的各种见解,我已经登上了这个怪物.即使它跳过一些析构函数确实违反了标准,它也"有效".但是,在编译时检查每个跳过的析构函数都是微不足道的,所以...:
请参阅godbolt:https://godbolt.org/g/2LK2fa
// Let's make sure our std::variant implementation does nothing funky internally.
static_assert(std::is_trivially_destructible<std::variant<char, int>>::value,
"change_from_I …Run Code Online (Sandbox Code Playgroud) 以下代码块:
从技术上讲是无效的,因为std::get<>()不是线程安全的。参考:是否在`std :: tuple`上使用`std :: get <I>`保证对不同的`I`值是线程安全的?
据我所知,std::tuple<>现在和可预见的将来,在野外的一切努力实际上都是安全的。
#include <tuple>
#include <atomic>
#include <thread>
// Out of my control
using data_t = std::tuple<int, int, int, int>;
void foo(data_t);
//
int main() {
data_t landing;
std::atomic<int> completed = 0;
// Whichever thread pings last will be the one performing foo()
auto ping = [&](){
if(++completed == 4) {
foo(landing);
}
};
std::thread a([&](){ std::get<0>(landing) = 1; ping(); });
std::thread b([&](){ std::get<1>(landing) = 2; ping(); });
std::thread …Run Code Online (Sandbox Code Playgroud) 鉴于以下设置:
// ***** Library Code *****
#include <concepts>
template <std::invocable CbT>
struct delegated {
explicit constexpr delegated(CbT cb) : cb_(std::move(cb)) {}
private:
[[no_unique_address]] CbT cb_;
};
// ***** User Code *****
#include <iostream>
namespace {
inline constexpr void func() {}
}
struct MyFunc {
constexpr void operator()() const {}
};
int main() {
void (*func_ptr)() = func;
auto from_func = delegated{func};
auto from_func_ptr = delegated{func_ptr};
auto from_lambda = delegated{[](){}};
auto from_functor = delegated{MyFunc{}};
std::cout << "func: " << sizeof(from_func) << …Run Code Online (Sandbox Code Playgroud) 我目前正在与Visual Studio 2017进行斗争(/std:c++latest如果有任何帮助,请编译使用).
有问题的代码只是根据一些模板化constexpr函数的结果选择结构特化.GCC和clang编译它没有问题.
这是我的MCVE:
#include <type_traits>
struct A {
enum {
test_trait = true
};
};
template<typename T>
constexpr int choose() {
return T::test_trait;
}
template<typename T, typename Enable=void>
struct Chosen;
template<typename T>
struct Chosen<T, std::enable_if_t<choose<T>() == 1>> {};
void foo() {
// This works
constexpr int chosen = choose<A>();
static_assert(chosen == 1, "");
// This resolves to the undefined struct.
using Chosen_t = Chosen<A>;
Chosen_t x;
(void)x;
}
Run Code Online (Sandbox Code Playgroud)
choose()在我的代码库中实际上有点复杂,但static_assert仍然编译,并检查正常.
我有点假设,如果static_assert …
如果我在Ubuntu 16.04/gcc 7.3中编译以下内容
struct VecA {
float data[4];
};
struct VecB {
float x;
float y;
float z;
float w;
};
// Requires stack protection
VecA getA() {return {1.0f, 1.0f, 1.0f, 1.0f};}
// Does not require stack protection
VecB getB() {return {1.0f, 1.0f, 1.0f, 1.0f};}
Run Code Online (Sandbox Code Playgroud)
像这样:
g++ -O3 -c -o result test.cpp
objdump -d result
Run Code Online (Sandbox Code Playgroud)
我明白了:
0000000000000000 <_Z4getAv>:
0: 48 83 ec 18 sub $0x18,%rsp
4: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
b: 00 00
d: 48 …Run Code Online (Sandbox Code Playgroud) 具体来说,我在一个友好的C++包装器中包装一个C API.C API具有相当标准的形状:
struct foo {...};
void get_foos(size_t* count, foo* dst);
Run Code Online (Sandbox Code Playgroud)
而且我有什么喜欢做的,是通过传递一个类型化punned包装拯救自己的额外拷贝阵列直接到C API和一群健全检查static_assert().
class fooWrapper {
foo raw_;
public:
[...]
};
std::vector<fooWrapper> get_foo_vector() {
size_t count = 0;
get_foos(&count, nullptr);
std::vector<fooWrapper> result(count);
// Is this OK?
static_assert(sizeof(foo) == sizeof(fooWrapper), "");
static_assert(std::is_standard_layout<fooWrapper>::value, "");
get_foos(&count, reinterpret_cast<foo*>(result.data()));
return result;
}
Run Code Online (Sandbox Code Playgroud)
我的理解是它是有效的代码,因为所有访问的内存位置都符合规则,但我想确认.
编辑:显然,只要reinterpret_cast<char*>(result.data() + n) == reinterpret_cast<char*>(result.data()) + n*sizeof(foo)是真的,它将在今天的所有主要编译器下工作.但我想知道标准是否同意.
来自http://eel.is/c++draft/class.member.lookup#1:
甲搜索在范围
X为名称N从程序点P是在单个搜索X用于N从P除非X是一个类或类模板的范围T,在这种情况下,下面的步骤定义搜索的结果。[注 1:结果只有在
N是转换函数 id或单次搜索找不到任何东西时才会有所不同。—尾注]
我很难理解 Note。似乎从类范围中进行“单一搜索”会在名称空间范围内找到前面的声明,因为名称空间范围包含类范围。但是,正如我们所知,如果名称也被声明为非依赖基类的成员,则基类成员优先于命名空间成员。Note 1似乎与此相矛盾,因为它基本上是在说“如果N不是转换函数 ID,那么您可以只进行普通的单一搜索,并且只有在找不到任何内容时,才使用本节中的过程”。但是单次搜索将通过找到命名空间范围声明而成功,而类成员查找将产生不同的结果。
我的理解错误在哪里?
我的开发机器上安装了Steam,它SteamOverlayVulkanLayer64作为隐式层安装.
这一切都很好,花花公子,但似乎最近的更新做了一个改变,使它与LunarG不兼容VKLayer_unique_objects.(至少就交换链创建在Windows上而言).
是否有一种理智的方法来禁用那个隐式层而不在我的机器上进行系统范围的更改?
作为参考,我正在使用1.1.77.0 SDK,以防任何方式相关.
编辑: 如果其他人碰到这个并且落在这里的可能性很小,可以使用环境变量控制蒸汽覆盖:
if (!validation_layers.empty()) {
#ifdef WIN32
// Steam's overlay is incompatible with LunarG's
SetEnvironmentVariable("DISABLE_VK_LAYER_VALVE_steam_overlay_1", "1");
#endif
[...]
}
Run Code Online (Sandbox Code Playgroud)
但是,我仍然有兴趣知道是否有一种控制隐式层的方法.
在 ubuntu 20.04 (10.0.0) 中打包的 clang-tidy 似乎在一个相当简单的代码块上窒息,它涉及结构化绑定和移动操作:
#include <memory>
#include <tuple>
struct T {
~T() {
if(ptr != nullptr) { // clang-tidy is convinced ptr is uninitialized when the tuple is destroyed.
}
}
T(T&& rhs) : ptr(rhs.ptr) {
rhs.ptr = nullptr;
}
// Be very explicit for the sake of the MCVE.
T() = default;
T(const T&) = delete;
T& operator=(T&&) = delete;
T& operator=(const T&) = delete;
int* ptr = nullptr;
};
std::tuple<T, T> foo();
void bar() { …Run Code Online (Sandbox Code Playgroud) 我正在尝试通过C ++和OpenCV使用我的网络摄像头,但我开始出现此错误
(...):Images.cpp :(。text + 0x27):对cv :: VideoCapture :: VideoCapture(int)的未定义引用
(...):Images.cpp :(。text + 0x38):对cv :: VideoCapture ::〜VideoCapture()的未定义引用
(...):Images.cpp :(。text $ _ZN2cv6StringD1Ev [_ZN2cv6StringD1Ev] + 0x11):对cv :: String :: deallocate()的未定义引用...
我的代码:
#include <iostream>
#include <string.h>
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/videoio/videoio.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/video.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
int main(int argc, char const *argv[])
{
VideoCapture cap(0);
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我刚刚开始使用 travis-CI,所以如果这是一个愚蠢或明显的问题,我深表歉意。
按照此处的说明操作:
我写了以下travis.yml
language: cpp
dist: trusty
matrix:
include:
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
- os: linux
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-trusty-5.0
packages:
- clang-5.0
env:
- MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"
before_install:
- eval "${MATRIX_EVAL}"
script:
- mkdir build
- cd build
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON ..
- cmake --build .
- ctest
Run Code Online (Sandbox Code Playgroud)
这会导致在 clang 构建中出现以下错误:
/home/travis/build/FrancoisChabot/abulafia/./include/abulafia/support/type_traits.h:20:12: 错误:命名空间“std”中没有名为“decay_t”的成员;您指的是 'decay' 吗?
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:1725:11: 注意: 'decay' 声明这里 …
我有以下代码,它可以工作,但是 C++20 版本看起来并不比 C++17 版本好多少。我的猜测问题是multimap equal_range返回 apair并且范围无法确定这是一对有效的迭代器。
有没有办法用更短更好的方式来写这个?
#include <iostream>
#include <map>
#include <ranges>
int main() {
std::multimap<bool,int> oddness{{false,2}, {true,3}, {true,47}, {false,74656}};
// nice, does not work:
// oddness.equal_range(true) | std::views::values;
// works:
oddness | std::views::values;
// working code:
auto odds = oddness.equal_range(true);
const auto odds_view = std::views::values(std::ranges::subrange(odds.first, odds.second));
for (const auto& odd : odds_view) {
std::cout << odd << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)