标签: c++17

使一个函数接受一个可选的接受非可选的?

我正在尝试以monad风格编写语法糖std::optional.请考虑:

template<class T>
void f(std::optional<T>)
{}
Run Code Online (Sandbox Code Playgroud)

即使存在从22的转换,也不能使用非可选T1(例如an int)调用此函数.Tstd::optional<T>

有没有办法f接受a std::optional<T>或a T(在调用者站点转换为可选),而没有定义过载3


1) f(0):error: no matching function for call to 'f(int)'note: template argument deduction/substitution failed,(演示).
2)因为模板参数推导不考虑转换.
3)超载是用于一个一元函数的可接受的解决方案,但开始是当你有像二进制功能的烦恼operator+(optional, optional),并且是用于三元疼痛,4元,等等功能.

c++ templates optional template-argument-deduction c++17

47
推荐指数
4
解决办法
2765
查看次数

此代码是否应该无法在C ++ 17中编译?

我正在更新一个项目以使用C ++ 17,发现一些实例,遵循该模式的代码在最新版本的clang上导致了编译错误:

#include <boost/variant.hpp>

struct vis : public boost::static_visitor<void>
{
    void operator()(int) const { }
};

int main()
{
    boost::variant<int> v = 0;
    boost::apply_visitor(vis{}, v);
}
Run Code Online (Sandbox Code Playgroud)

在C ++ 17模式下使用clang v8.0,此操作失败,并显示以下错误

<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
    boost::apply_visitor(vis{}, v);
                             ^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
    ~static_visitor() = default;
Run Code Online (Sandbox Code Playgroud)

但是,它可以在C ++ 14模式下干净地编译。我发现如果将花括号初始化更改vis{}为括号vis(),则可以在两种模式下正确编译。我尝试过的每个gcc版本都允许在C ++ 17模式下使用这两种变体。

这是从C ++ 14到C ++ 17的正确行为更改,还是这是一个叮当响的错误?如果正确,为什么现在在C ++ 17中无效(或者也许一直如此,但是clang仅在较早的标准版本中允许使用)?

c++ clang boost-variant c++17

46
推荐指数
1
解决办法
3087
查看次数

为什么在C ++ 20中std :: move没有[[nodiscard]]?

我最近阅读了[[nodiscard]]C ++ 17,据我了解,它是一项新功能(按合同设计吗?),它迫使您使用返回值。对于有争议的函数std::launder(从C ++ 20开始不丢弃),这是有意义的,但是我想知道为什么std::move在C ++ 17/20 中没有这样定义。您知道很好的理由还是因为C ++ 20尚未完成?

c++ language-lawyer c++17 c++20

45
推荐指数
2
解决办法
1869
查看次数

哪里使用std :: variant而不是union?

请解释之间有什么区别unionstd::variant为什么 std::variant引入标准?我们应该在什么情况下使用std::variant旧学校union

c++ c++17

44
推荐指数
1
解决办法
8125
查看次数

我应该将std :: string与“ string”或“ string” s比较吗?

考虑以下代码片段:

bool foo(const std::string& s) {
    return s == "hello"; // comparing against a const char* literal
}

bool bar(const std::string& s) {
    return s == "hello"s; // comparing against a std::string literal
}
Run Code Online (Sandbox Code Playgroud)

乍一看,它看起来像比对并const char*需要更少的组装说明1,作为使用字符串字面量会导致就地建设std::string

编辑:正如答案中指出的那样,我忘记了有效地s.compare(const char*)将被调用的事实foo(),因此在这种情况下当然不会进行就地构建。因此,请在下面删除一些行。

但是,请operator==(const char*, const std::string&)参阅参考资料:

所有比较都是通过compare()成员函数完成的。

根据我的理解,这意味着我们将需要构造一个结构std::string来执行比较,因此我怀疑最终的开销将是相同的(尽管对的调用已将其隐藏了operator==)。

  • 我应该选择哪个比较?
  • 一个版本是否比另一个版本具有优势(可能在特定情况下)?

1我知道更少的汇编指令并不一定意味着更快的代码,但是我不想在这里进行微基准测试。

c++ string-comparison string-literals c++14 c++17

44
推荐指数
3
解决办法
2894
查看次数

为什么在c ++ 17中不推荐使用std :: allocator的构造和销毁函数?

c ++ 17规范不赞成使用对象constructdestroy成员std::allocator.用于弃用其他成员函数工作组提供的基本原理这里,标题下的"弃用的std ::分配器的所述冗余成员".

但是,他们没有具体提到为什么这两个成员被弃用或者建议取代该功能的原因.我假设暗示是用来std::allocator_traits::construct代替.

我有点困惑的construct是,在某些情况下实施是否仍然是必要的,尽管因为这个评论std::allocator_traits::construct

因为此函数提供自动回退到placement new,所以成员函数construct()是自C++ 11以来的可选Allocator要求.

对于自定义分配器(例如,对于页面对齐的内存使用memalign),回退到放置new总会产生正确的行为吗?

c++ memory-management allocator language-lawyer c++17

43
推荐指数
2
解决办法
4354
查看次数

什么是标准名称?

据我所知,标准中没有提及“ 完全合格 ”一词(例如),但我可以记得在网上多次“听到”它。

人们说一个名字完全合格是什么意思?

这算吗?

A::f()
Run Code Online (Sandbox Code Playgroud)

还是只有这个?

::A::f()
Run Code Online (Sandbox Code Playgroud)

而且,如果这标准的,我找不到哪个措辞?

c++ language-lawyer c++17

43
推荐指数
2
解决办法
2429
查看次数

使用 C++20 三路比较进行更多无声行为改变

令我惊讶的是,我遇到了另一个障碍,例如C++20 行为用相等运算符破坏了现有代码?.

考虑一个简单的不区分大小写的键类型,用于例如std::setor std::map

// Represents case insensitive keys
struct CiKey : std::string {
    using std::string::string;
    using std::string::operator=;

    bool operator<(CiKey const& other) const {
        return boost::ilexicographical_compare(*this, other);
    }
};
Run Code Online (Sandbox Code Playgroud)

简单的测试:

using KeySet   = std::set<CiKey>;
using Mapping  = std::pair<CiKey, int>; // Same with std::tuple
using Mappings = std::set<Mapping>;

int main()
{
    KeySet keys { "one", "two", "ONE", "three" };
    Mappings mappings {
        { "one", 1 }, { "two", 2 }, { "ONE", 1 }, { "three", …
Run Code Online (Sandbox Code Playgroud)

c++ spaceship-operator stdtuple c++17 c++20

43
推荐指数
2
解决办法
2549
查看次数

使用observer_ptr

std::observer_ptr库基础技术规范V2 中的构造究竟有什么意义?

在我看来,它所做的一切都是裸露的T*,如果不增加动态内存安全性,这似乎是一个多余的步骤.

在我的所有代码中,我使用std::unique_ptr了我需要明确拥有对象的位置以及std::shared_ptr可以共享对象所有权的位置.

这非常有效并且可以防止意外解除引用已经被破坏的对象.

std::observer_ptr 当然,不保证观察到的物体的寿命.

如果它是从a构造的,std::unique_ptr或者std::shared_ptr我会看到在这样的结构中使用,但任何简单使用的代码T*可能只是继续这样做,如果他们计划移动到任何它将是std::shared_ptr和/或std::unique_ptr(取决于在使用上).


给出一个简单的示例函数:

template<typename T>
auto func(std::observer_ptr<T> ptr){}
Run Code Online (Sandbox Code Playgroud)

如果停止智能指针在观察它们时销毁它们存储的对象将会有用.

但如果我想观察std::shared_ptrstd::unique_ptr我必须写:

auto main() -> int{
    auto uptr = std::make_unique<int>(5);
    auto sptr = std::make_shared<int>(6);
    func(uptr.get());
    func(sptr.get());
}
Run Code Online (Sandbox Code Playgroud)

这使得它不比以下更安全:

template<typename T>
auto func(T *ptr){}
Run Code Online (Sandbox Code Playgroud)

那么,这个新结构的用途是什么?

它只是用于自我记录的来源吗?

c++ smart-pointers c++17

42
推荐指数
5
解决办法
6748
查看次数

限制可变参数模板参数

我们可以将可变参数模板参数限制为某种类型吗?即,实现类似的东西(当然不是真正的C++):

struct X {};

auto foo(X... args)
Run Code Online (Sandbox Code Playgroud)

在这里,我的目的是拥有一个接受可变数量X参数的函数.

我们最接近的是:

template <class... Args>
auto foo(Args... args)
Run Code Online (Sandbox Code Playgroud)

但是这接受任何类型的参数.

c++ templates c++-faq variadic-templates c++17

41
推荐指数
2
解决办法
3740
查看次数