小编Bar*_*rry的帖子

此代码是否应该无法在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
查看次数

类模板特化部分排序和函数合成

选择哪个类模板特化的首选规则包括将特化重写为函数模板,并通过函数模板[temp.class.order]的排序规则确定哪个函数模板更加专业化.考虑这个例子,然后:

#include <iostream>

template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;

template <class T, class U> struct A { };

template <class T> int foo(A<T, void_t<T>> ) { return 1; }
template <class T> int foo(A<T*, void> )     { return 2; }

int main() {
    std::cout << foo(A<int*, void>{});
}
Run Code Online (Sandbox Code Playgroud)

gcc和clang都打印2在这里.这是有道理的一些前面的例子-推导对非推测的情况下(voidvoid_t<T>)只是忽略,所以推断<T, void_t<T>>反对<X*, void>成功,但推断<T*, void>针对<Y, void_t<Y>>在两个参数失败.精细. …

c++ templates partial-ordering language-lawyer

43
推荐指数
1
解决办法
1416
查看次数

要求虚函数覆盖使用override关键字

添加override了C++ 11 以确保您编写的要覆盖基类虚函数的成员函数实际上(或不会编译).

但是在大型对象层次结构中,有时您可能会意外地编写一个成员函数,当您不想要它时会覆盖基类虚拟!例如:

struct A {
    virtual void foo() { }  // because obviously every class has foo().
};

struct B : A { ... };

class C : B {
private:
    void foo() {
        // was intended to be a private function local to C
        // not intended to override A::foo(), but now does
    }
};
Run Code Online (Sandbox Code Playgroud)

是否有一些编译器标志/扩展名至少会发出警告C::foo?为了便于阅读和正确,我只想强制所有覆盖使用override.

c++ virtual gcc overriding c++11

42
推荐指数
3
解决办法
1万
查看次数

什么是shared_ptr的别名构造函数?

在此页面(http://www.cplusplus.com/reference/memory/shared_ptr/)第5段中,它说:

此外,shared_ptr对象可以在指向另一个对象的同时共享指针的所有权.此功能称为别名(请参阅构造函数),通常用于指向成员对象,同时拥有它们所属的对象.因此,shared_ptr可能与两个指针有关:

  • 存储指针,它是指向它的指针,以及它与运算符*取消引用的指针.

  • 一个拥有的指针(可能是共享的),它是所有权组在某个时刻负责删除的指针,并且它被视为一个用途.

通常,存储的指针和拥有的指针引用相同的对象,但是别名shared_ptr对象(使用别名构造函数及其副本构造的对象)可以引用不同的对象.

然后我读了这页(http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/)关于shared_ptr的别名构造函数.但我仍然认为这种"走样"行为令人困惑.为什么在这里?它是为了什么?在什么情况下我想要这个功能?

c++ c++11

40
推荐指数
1
解决办法
6994
查看次数

有状态的元编程是否形成不良(尚)?

我有幸遇到的最让我最喜爱/最邪恶的发明之一是constexpr计数器,也就是有状态的元编程.正如帖子中所提到的,它似乎在C++ 14下是合法的,我想知道C++ 17有什么变化吗?

以下是主要基于帖子的实现

template <int N>
struct flag
{
    friend constexpr int adl_flag(flag<N>);
    constexpr operator int() { return N; }
};

template <int N>
struct write
{
    friend constexpr int adl_flag(flag<N>) { return N; }
    static constexpr int value = N;
};

template <int N, int = adl_flag(flag<N>{})>
constexpr int read(int, flag<N>, int R = read(0, flag<N + 1>{}))
{
    return R;
}

template <int N>
constexpr int read(float, flag<N>)
{
    return N;
}

template <int N …
Run Code Online (Sandbox Code Playgroud)

c++ metaprogramming language-lawyer c++17

40
推荐指数
1
解决办法
2308
查看次数

为什么不推荐使用std :: iterator?

模板类std::iterator设置为在C++ 17中弃用.为什么这样?它是确保std::iterator_traits工作的一种方便方法,特别是如果您可以使用默认模板参数.在C++ 17中还有其他一些方法吗?

c++ c++17

39
推荐指数
2
解决办法
6165
查看次数

通用引用和转发引用之间有区别吗?

此函数的参数将绑定到右值引用:

void f(int && i);
Run Code Online (Sandbox Code Playgroud)

但是,此函数的参数将绑定到右值或左值引用:

template <typename T>  
void f(T && t);
Run Code Online (Sandbox Code Playgroud)

我经常听到这被称为通用参考.
我也听说它被称为转发参考.
他们的意思是一样的吗?
如果函数体调用,它只是转发引用std::forward吗?

c++ templates perfect-forwarding universal-reference forwarding-reference

37
推荐指数
2
解决办法
1万
查看次数

使用以前的函数参数来声明新函数是否合法?

以下代码与GCC完全编译:

void func(int arg1, decltype(arg1) arg2)
{
    (void)arg2;
}
int main(){}
Run Code Online (Sandbox Code Playgroud)

我用这个命令编译:

g++ -std=c++14 test.cpp -o test -pedantic-errors -Wall -Wextra
Run Code Online (Sandbox Code Playgroud)

但是在函数声明中间使用参数似乎很奇怪.它在标准C++中实际有效,还是GCC扩展?

c++ gcc function language-lawyer

35
推荐指数
3
解决办法
1441
查看次数

将联合重新解释为不同的联合

我有一个标准布局联合,其中包含一大堆类型:

union Big {
    Hdr h;

    A a;
    B b;
    C c;
    D d;
    E e;
    F f;
};
Run Code Online (Sandbox Code Playgroud)

每种类型的A直通F是标准布局和具有作为其第一元件类型的对象Hdr.该Hdr标识了工会的积极成员为,所以这是变体样.现在,我处于一种我确定知道的情况(因为我检查过),活跃成员是a B或a C.实际上,我已将空间减少到:

union Little {
    Hdr h;

    B b;
    C c;
};
Run Code Online (Sandbox Code Playgroud)

现在,是以下明确定义还是未定义的行为?

void given_big(Big const& big) {
    switch(big.h.type) {
    case B::type: // fallthrough
    case C::type:
        given_b_or_c(reinterpret_cast<Little const&>(big));
        break;
    // ... other cases here ...
    }
}

void given_b_or_c(Little const& little) {
    if (little.h.type == B::type) {
        use_a_b(little.b);
    } else …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++11

35
推荐指数
2
解决办法
1213
查看次数

处理gcc的noexcept-type警告

bug 80985开始考虑这个例子:

template <class Func>
void call(Func f)
{
    f();
}

void func() noexcept { }

int main()
{
    call(func);
}
Run Code Online (Sandbox Code Playgroud)

正如您所做的那样,在启用所有警告的情况下进行编译会产生:

$ g++ -std=c++14 -Wall foo.cxx 
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type]
 void call(Func f)
      ^~~~
Run Code Online (Sandbox Code Playgroud)

我应该怎么做这个警告呢?修复是什么?

c++ g++ noexcept c++17 gcc7

32
推荐指数
1
解决办法
3374
查看次数