小编Jun*_*eon的帖子

使用声明的奇怪行为

请参阅以下代码

struct A { using type = int; };
struct B : private A {};
struct C : B { using base_type = A; };
Run Code Online (Sandbox Code Playgroud)

所有的gcc 6.1,clang 3.8和msvc 2015更新3都拒绝编译它,因为A它不是一个可访问的名称,C因为它A是一个私有基础B.似乎gcc认为Ausing base_type = A指默认构造函数A.msvc和clang似乎没有.

也许编译错误是由于继承触发的名称注入(因为修改using base_type = Ausing base_type = ::A使所有编译器工作正常),但我想知道这个奇怪的错误是否是标准所说的.

更具体地说,

  1. 据我所知,不是A::type,A只是一个类名(虽然gcc误解为一个函数名),它不是引入C 内部 A也不引入B.为什么这个名字被认为是私人的B
  2. 该编译错误是否应被视为错误,或者是标准规范的边缘情况?

c++ using-declaration private-inheritance name-lookup c++11

26
推荐指数
1
解决办法
1200
查看次数

在模板类型推导之前评估noexcept说明符

请参阅以下代码:

#include <utility>

struct A {
  A(int, int) {}
};

struct tag {};

template <class... Args>
struct is_noexcept {
  static constexpr bool value = noexcept(A{std::declval<Args>()...});
};

struct B : A {
  //#1
  template <class... Args>
  B(tag, Args&&... args) noexcept(/*Here*/is_noexcept<Args...>::value) :
    A{std::forward<Args>(args)...} {}

  //#2
  B(int x, int y) : A{x, y} {}
};

int main()
{
  B x{0, 0};
}
Run Code Online (Sandbox Code Playgroud)

这段代码似乎被GCC/Clang接受,但MSVC 2017拒绝接受.似乎MSVC编译器试图理解是#1不是适当的过载(由于之间的不相容之前计算noexcept符tagint),因此应被丢弃.因此,它试图评估is_noexcept<int>::value并发现noexcept(A{std::declval<int>()})是不正确的.由于这不是在紧急情况下发生的,因此这不是SFINAE的用武之地,所以很难发生错误.

(其实,我不是很肯定这一点,但我已经证实,如果我把noexcept(A{std::declval<Args>()...}),而不是is_noexcept<Args...>::value/*Here*/做直接的上下文中发生故障时,MSVC编译器愉快地下降#1和#调用2.这是正确的? )

我怀疑GCC/Clang是对的,MSVC是错的,但哪一个是正确的?

c++ language-lawyer noexcept c++11

9
推荐指数
1
解决办法
196
查看次数

为什么成员函数不能用作模板参数?

为什么成员函数不能用作模板参数?例如,我想这样做:

struct Foo {
    void Bar() { // do something
    }
};
template <typename TOwner, void(&func)()>
void Call(TOwner *p) {
    p->func();
}
int main() {
    Foo a;
    Call<Foo, Foo::Bar>(&a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我知道使用指向成员的指针可以做类似的事情; 好吧,它大部分时间都很酷,但我只是好奇为什么指针"应该"使用.

我认为上面解释"p-> func()"没有含糊之处.为什么该标准禁止我们使用成员函数作为模板参数?根据我的编译器(VC++ 2013),甚至不允许使用静态成员函数.有谁知道原因?或者,有没有办法做同样的事情而不会因指针解除引用而失去任何性能?

谢谢.

c++ templates member-functions

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

拥有一个C样式数组的std ::数组是否合法?

我可以使用类似std::array<int[2][2], 2>替代品的东西int[2][2][2],就像std::array<int, 2>可以用来代替int[2]吗?

我真正需要的可能是一个静态大小的多维数组

  1. 具有"适当的"价值语义,并且
  2. 被连续存储在内存中.

看来,这与C风格的数组,std::arraystd::array不能保证有充分紧凑化存储,因为std::array可能含有填充.

如果我使用类似的东西,可能会遇到什么问题std::array<int[2][2], 2>?也许这是一个太模糊的问题,但很难弄清楚为什么我不舒服,有些怀疑使用它为我的目的.

c++ arrays

7
推荐指数
1
解决办法
199
查看次数

在现代 C++ 中重载算术运算符的“最佳”方法是什么?

我想在 C++ 中实现一种“类似数字”的数学对象(例如,组或环中的元素)。我确信我不是唯一处理这个问题的人,因此可能会有大量关于重载算术运算符的“最佳”方法的讨论。然而,我找不到满意的答案(尽管也许我懒得去谷歌搜索更多)。

假设我想为 A 类重载运算符“+”。问题是,我能想到太多不同的重载:

  1. 运算符+(常量 A& x, 常量 A& y)
  2. 运算符+(const A& x, A&& y)
  3. 运算符+(A&& x, const A& y)
  4. 运算符+(A&& x, A&& y)
  5. A::运算符+=(const A& y) &
  6. A::运算符+=(const A& y) &&
  7. A::运算符+=(A&& y) &
  8. A::运算符+=(A&& y) &&

第一个问题。所有这些重载是否都需要使 A 实例上的操作尽可能高效并尽可能“像原始类型”?我认为对于“普通”情况,右值限定的 A::operator+= 不需要(或不应该)重载。这样对吗?我认为1-4都是必要的。例如,对于情况3,由于x正在被移动,我们不需要分配新的空间来保存返回值,并且我们可以安全地重用为x保留的分配存储。这样对吗?

第二个问题。我认为对于大多数此类情况,所有这些重载可能共享大量代码。如何在不牺牲性能等的情况下最大限度地减少代码重复?有什么特殊的技巧/习惯可以做到这一点吗?我更喜欢通用和可扩展的方法(如果存在)。

arithmetic-expressions operator-overloading move-semantics c++11

6
推荐指数
1
解决办法
4448
查看次数

继承嵌套模板类的专业化

以下源代码来自: 了解继承的嵌套类模板的部分特化

#include <type_traits>
struct Base
{
    template<class U, class _ = void> struct Inner: std::true_type {};
    template<class _> struct Inner<char, _>: std::false_type {};
};
struct Derived : Base
{
};

template<class _> struct Derived::Inner<int, _>: std::false_type {};
Run Code Online (Sandbox Code Playgroud)

我有一个关于专门继承类的问题,所以我用Google搜索,并找出上面的问题.上面问题中的源代码没有编译gcc/clang中的任何问题,但msvc拒绝编译它,发出C2427(参见 https://msdn.microsoft.com/en-us/library/10het5hx.aspx).

上面的情况(专门化非模板类的嵌套模板类)与https://msdn.microsoft.com/en-us/library/10het5hx.aspx中描述的情况完全不同(定义嵌套的非我认为,模板类的模板类).

msvc与gcc/clang中哪一个错了?或者只是标准是如此不明确指定这种行为?

我希望msvc错了......

c++ inheritance inner-classes template-specialization language-lawyer

6
推荐指数
1
解决办法
388
查看次数

如何正确推导出一个函数的noexcept-ness?

在通用上下文中,我们经常写类似的东西

return_type f(arg_type1 arg1, ...)
  noexcept(noexcept(statement_1) && noexcept(statement_2) && ... && noexcept(statement_n))
{
  statement_1;
  statement_2;
  ...
  statement_n;
}
Run Code Online (Sandbox Code Playgroud)

当a statement_k是return语句时,事情并非如此简单.这是不可能写的noexcept(return expr).相反,我应该理解当我们说return expr并分解成几个时发生的事情noexcept(something).但它似乎非常重要.

我想出了类似下面的算法:

  1. 如果return_type是参考类型,那么当然noexcept(expr)就足够了.
  2. 如果return_type不是参考类型,但如果return expr是保证复制省略发生的情况,那么再次noexcept(expr)就足够了.
  3. 否则,noexcept(expr) && std::is_nothrow_move_constructible<return_type>::value && std::is_nothrow_destructible<return_type>::value.

这样对吗?或者有更简单的方法吗?案例1将被归入案例3的特例,但案例2和案例3如何?

c++ noexcept copy-elision c++17

6
推荐指数
0
解决办法
108
查看次数

为什么调用复制构造函数而不是移动构造函数?

请查看以下示例代码:

   #include <iostream>

    struct Foo {
        Foo() { std::cout << "Default!\n"; }
        Foo(const Foo& foo) { std::cout << "Copy!\n"; }
        Foo(Foo&& foo) { std::cout << "Move!\n"; }
    };

    struct Bar {
        Foo foo;
        Bar() {}
        Bar(Bar &that) : foo(that.foo) {}
        Bar(Bar &&that) : foo(std::move(that.foo)) {}
    };

    Bar f() {
        Bar bar;
        return bar;
    }

    int main() {
        Bar bar(f());
    }
Run Code Online (Sandbox Code Playgroud)

我希望这段代码的输出应该是:

Default!
Move!
Run Code Online (Sandbox Code Playgroud)

但我得到的是:

Default!
Copy!
Run Code Online (Sandbox Code Playgroud)

我看不出为什么调用复制构造函数而不是移动构造函数的原因.如果我把关键字const放在Bar &that复制构造函数的声明前面struct Bar,我就得到了正确的结果.我知道在很多情况下采用const左值引用而不仅仅是复制构造函数的左值引用更好,但我只是想知道发生这种情况的原因.

为什么在这个例子Bar &中被优先考虑,Bar …

copy-constructor rvalue-reference move-semantics rvo c++11

5
推荐指数
2
解决办法
2548
查看次数

STL 容器的右值引用限定符

为什么元素访问 STL 容器的成员函数,例如std::array::operator[]std::vector::operator[]没有右值引用限定符重载?当然我可以做std::move(generate_vector()[10]),但我很好奇在标准化引用限定符时是否考虑添加右值引用限定符重载。

我认为std::array<T, N>std::tuple<T, T, ..., T>真的是一回事,std::get后者的“元素访问函数(即)”对于 const 与非常量以及左值与右值的所有组合都被重载。为什么不是前者?

将右值引用限定的元素访问成员函数(返回右值引用)添加到我的自定义容器是个好主意吗?

编辑

对于理查德克里滕的评论。我认为这有时会很有用。

例如,您有一个函数返回在该函数内部构造的容器,但您可能只对该容器的第一个元素感兴趣。是的,这很愚蠢。在这种情况下,最好使用仅构造第一个元素的更简单的函数。但是如果这个功能不是你的,你就没有这样的选择。

或者,可能有更一般的例子。您有一个构造容器的函数,并且您希望处理该容器以获得另一个结果。例如,您可能希望执行std::reduce, 或std::unique_copy到那个容器。(似乎在执行期间禁止修改元素std::reduce,但让我们假设我们已经实现了允许修改的元素。)在这种情况下,可以使用std::make_move_iterator,但为什么不让容器本身返回移动迭代器呢?

编辑2

事实上,当我将一些“视图”类实现到容器类时,我遇到了这个问题。可变视图(左值引用)、不可变视图(常量引用)和可移动视图(右值引用)似乎都需要,我必须确定从可移动视图类的元素访问成员函数返回什么:左值或右值引用? 我觉得有点奇怪,将右值引用返回到容器本身没有公开此类接口的元素。哪一个是正确的?

  1. 左值引用。
  2. 右值引用。
  3. 移动视图,一般来说是不对的。这种东西不应该经常需要,我的设计应该有一些严重的问题。

c++ stl ref-qualifier

5
推荐指数
1
解决办法
520
查看次数

在模板派生类中使用类型别名继承构造函数

请参见以下代码:

struct base {};

template <class T>
struct derived : T {
  using base_type = T;
  using base_type::T;
};

int main()
{
  derived<base> x;
}
Run Code Online (Sandbox Code Playgroud)

GCC接受此代码,但是Clang和MSVC拒绝它。谁是正确的,为什么?

c++ language-lawyer c++11 inheriting-constructors

4
推荐指数
1
解决办法
119
查看次数

为什么UTF-8编码不使用11111xxx格式的字节作为第一个字节?

根据https://en.wikipedia.org/wiki/UTF-8,字符编码的第一个字节永远不会以10xxxxxx和11111xxx的位模式开始.第一个的原因很明显:自动同步.但第二个怎么样?是否可以像潜在的扩展一样启用5字节编码?

utf-8 utf

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