小编Han*_*Han的帖子

Why isn't std::variant allowed to equal compare with one of its alternative types?

For example, it should be very helpful to equal compare a std::variant<T1, T2> with a T1 or T2. So far we can only compare with the same variant type.

c++ c++17 std-variant

8
推荐指数
3
解决办法
415
查看次数

在未评估的上下文中在 lambda 中使用 std::declval 是否合法?

下面的代码或在godbolt上的代码可以使用 gcc 和 MSVC 进行编译,但会因 clang 失败。我找不到标准中是否/哪里禁止它。我认为应该支持。

那么,clang 和 gcc/MSVC 谁的说法是正确的呢?

#include <type_traits>

void foo() {
    static_assert(decltype([_=std::declval<int>()]() consteval noexcept { // clang error: declval() must not be used
        if constexpr (std::is_integral<decltype(_)>::value) {
            return std::bool_constant<true>();
        } else {
            return std::bool_constant<false>();
        }
    }())::value);
}
Run Code Online (Sandbox Code Playgroud)

该示例可以扩展为以下 3 种情况或在godbolt上:

  1. 作为 lambda 调用参数:可以使用 clang/gcc/MSVC
  2. 作为 lambda 捕获:gcc/MSVC 正常,clang 错误
  3. 在 lambda 主体中:clang/gcc/MSVC 错误

因此,很明显,它在 lambda 主体中不合法,但在外部作为调用者参数是合法的。目前尚不清楚捕获列表中是否允许。

#include <type_traits>

auto foo_lambda_argument() {
    return decltype([](auto _) noexcept {
        return std::bool_constant<std::is_integral<decltype(_)>::value>();
    }(std::declval<int>()))::value; // OK …
Run Code Online (Sandbox Code Playgroud)

c++ lambda language-lawyer c++20 declval

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

SFINAE方法完全禁用了clang中的基类模板方法

#include <iostream>
#include <utility>

struct B {
    template<typename T, std::enable_if_t<std::is_same<T, int>::value>* = nullptr>
    void foo(T) {
        std::cout<<"B::foo"<<std::endl;
    }
};

struct D: B {        
    using B::foo;
    template<typename T, std::enable_if_t<std::is_same<T, std::string>::value>* = nullptr>
    void foo(T) {
        std::cout<<"D::foo"<<std::endl;
    }
};

int main() {
    D d;
    d.foo(2); // gcc: print "B::foo"; clang: compile error
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

假设我们想foo()在派生类D中公开两个重载.gcc和Visual Studio编译并按照我的预期打印"B :: foo".但我得到一个与clang编译错误:

prog.cc:22:7: error: no matching member function for call to 'foo'
    d.foo(2);
    ~~^~~
prog.cc:14:10: note: candidate template ignored: requirement 'std::is_same<int, std::string>::value' was …
Run Code Online (Sandbox Code Playgroud)

c++ gcc clang language-lawyer c++11

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

具有 xvalue 操作数的三元运算符

假设我们有一个带有 2 个 xvalue 操作数的三元运算符。

struct A {
    A() { std::cout<<"A ctor"<<std::endl; }
    ~A() { std::cout<<"A dtor"<<std::endl; }
    A(A const&) { std::cout<<"A copy ctor"<<std::endl; }
    A(A&&) { std::cout<<"A move ctor"<<std::endl; }

    void foo() & { std::cout<<"A&.foo()"<<std::endl; }
    void foo() const& { std::cout<<"A const&.foo()"<<std::endl; }
    void foo() && { std::cout<<"A&&.foo()"<<std::endl; }
    void foo() const&& { std::cout<<"A const&&.foo()"<<std::endl; }
};

int main()
{
    A a;
    A a2;
    (true? static_cast<A&&>(a) : static_cast<A&&>(a2)).foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

根据cppreference条件运算符

4) 如果 E2 和 E3 是相同类型和相同值类别的左值,则结果具有相同类型和值类别,并且如果 E2 …

c++ c++11 c++14 c++17 value-categories

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

C++20 函数尾随返回类型和 noexcept 运算符中是否允许 lambda 捕获?

下面的简单代码或godbolt与 gcc、clang 和 Visual Studio 具有不同的结果。

auto foo1(int n) -> decltype(([n]() { return n+1; }()))
// gcc error: use of parameter outside function body before '+' token
{
    return [n]() { return n+1; }();
}

auto foo2(int n) -> decltype(([&n]() { return n+1; }()))
// gcc error: use of parameter outside function body before '+' token
{
    return [&n]() { return n+1; }();
}

auto foo3(int n) -> decltype(([&]() { return n+1; }()))
// gcc error: use of …
Run Code Online (Sandbox Code Playgroud)

c++ lambda trailing-return-type c++20

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

可以通过 c++17 中的 using 声明继承复制/移动构造函数吗?

struct B {
  B(int) {}
  B(B const&) {}
};

struct D: B {
  using B::B;
};

int main(void) {
  B b(5);
  D d(b); // error
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

c++14 在 12.9 [class.inhctor]/p3 中明确从继承的构造函数中排除复制/移动构造函数。

对于候选继承构造函数集中的每个非模板构造函数(除了没有参数的构造函数或具有单个参数的复制/移动构造函数之外),构造函数将隐式声明为具有相同的构造函数特征,除非存在用户声明的构造函数完整类中出现 using 声明的相同签名,或者构造函数将是该类的默认构造函数、复制构造函数或移动构造函数。

但我在c++17中找不到任何详细的描述。clang/gcc 显示基类的复制/移动构造函数不是继承的。有人可以提供标准中的解释吗?谢谢。

c++ language-lawyer inherited-constructors c++14 c++17

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

可变数据成员、模板构造函数和普通复制构造函数

示例代码可以在下面或godbolt上找到。假设我们有 4 个班级:

  1. S<T>:持有数据成员。

  2. SCtor<T>:持有数据成员并具有模板构造函数。

  3. SCtorMutable<T>:持有可变数据成员并具有模板构造函数。

  4. SCtorDefault<T>:持有一个成员,有一个模板构造函数,有默认的复制/移动构造函数和默认的复制/移动赋值运算符。

所有编译器都同意这 4 个类是可以简单复制的。

如果有一个简单的包装类W<T>将上述任何一个类作为数据成员。包装类W<S...<T>>仍然是可简单复制的。

如果有另一个包装类WMutable<T>将上述类中的任何一个保存为可变数据成员。

  1. MSVC 仍然认为WMutable<S...<T>>是可以简单复制的。
  2. clang 认为WMutable<S<T>>是可以复制的。WMutable<SCtor...<T>>不是可简单复制构造的,因此也不是可简单复制的。
  3. gcc 认为WMutable<S<T>>是可以简单复制的。WMutable<SCtor...<T>>不是可简单复制构造的,而是可简单复制的。

应该WMutable<T>是可以简单复制的吗?

#include <type_traits>
#include <utility>

template<typename T>
struct S {
    T m_t;
};

template<typename T>
struct SCtor {
    T m_t;
    template<typename... U>
    SCtor(U&&... u): m_t(std::forward<U>(u)...) {}
};

template<typename T>
struct SCtorMutable {
    mutable T m_t;
    template<typename... U> …
Run Code Online (Sandbox Code Playgroud)

c++ mutable copy-constructor language-lawyer trivially-copyable

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

当 require 子句失败时,函数尾随返回类型是否被评估

下面或godbolt上的简单代码不能用 clang 编译,但可以用 gcc 和 Visual Studio 编译良好。

当 SFINAE 使用 clang、gcc 和 Visual Studio 失败时,不会评估 的尾随返回类型decltype(foo(t))baz(T t)

但是,当 require 子句因 clang 失败时,仍会评估 的尾随返回decltype(foo(t))类型。bar(T t)当 gcc 和 Visual Studio 的 require 子句失败时,不会评估尾随返回类型。哪个编译器对此是正确的?

谢谢。

#include <utility>
#include <type_traits>

template<typename T>
auto foo(T) {
    static_assert(std::is_integral<T>::value); // clang error: static_assert failed due to requirement 'std::is_integral<double>::value'
    return 5;
}
 
template<typename T> requires std::is_integral<T>::value
auto bar(T t) -> decltype(foo(t)) {
    return foo(t);
}

template<typename T> requires …
Run Code Online (Sandbox Code Playgroud)

c++ sfinae c++-concepts c++20

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

c++20 默认比较运算符和空基类

c++20默认的比较运算符是一个非常方便的功能。但我发现如果该类有一个空的基类,它就没那么有用了。

默认运算符 <=> 通过连续比较 T 的基类(从左到右深度优先)和非静态成员(按声明顺序)子对象来计算 <=> 来执行字典比较,递归扩展数组成员(在下标递增的顺序),并在发现不相等的结果时提前停止

根据标准,SComparable如果没有运算符<=>,则不base会有运算符<=>。在我看来,为空类定义比较运算符是没有意义的。因此,默认的比较运算符不适用于具有空基类的类。

struct base {};

struct SComparable: base {
  int m_n;
  auto operator<=>(SComparable const&) const& = default; // default deleted, clang gives a warning
};

struct SNotComparable: base {
  int m_n;
};
Run Code Online (Sandbox Code Playgroud)

如果我们迫切需要使用默认比较运算符,因此为空基类定义比较运算符base。另一个派生类SNotComparable由于其空基类而错误地变得具有可比性base

struct base {
  auto operator<=>(base const&) const& = default;
};

struct SComparable: base {
  int m_n;
  auto operator<=>(SComparable const&) const& = default;
};

struct SNotComparable: base { // SNotComparable is …
Run Code Online (Sandbox Code Playgroud)

c++ spaceship-operator c++20 default-comparisons

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

如何编写一个boost :: spirit :: qi解析器来解析从0到std :: numeric_limits &lt;int&gt; :: max()的整数范围?

我尝试使用qi::uint_parser<int>()。但这是一样的qi::uint_。它们都匹配从0到的整数std::numeric_limits<unsigned int>::max()

qi::uint_parser<int>()设计成这个样子?我应该使用什么解析器来匹配从0到的整数范围std::numeric_limits<int>::max()?谢谢。

c++ parsing numeric boost-spirit boost-spirit-qi

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

递归x3解析器,结果传递

(1)假设我们要解析一个简单的递归块{}.

{
    Some text.
    {
        {
            Some more text.
        }
        Some Text again.
        {}
    }
}
Run Code Online (Sandbox Code Playgroud)

这个递归解析器非常简单.

x3::rule<struct idBlock1> const ruleBlock1{"Block1"};
auto const ruleBlock1_def =
    x3::lit('{') >>
    *(
        ruleBlock1 |
        (x3::char_ - x3::lit('}'))
    ) >>
    x3::lit('}');

BOOST_SPIRIT_DEFINE(ruleBlock1)
Run Code Online (Sandbox Code Playgroud)

(2)然后块变得更复杂.它也可能被包围[].

{
    Some text.
    [
        {
            Some more text.
        }
        Some Text again.
        []
    ]
}
Run Code Online (Sandbox Code Playgroud)

我们需要在某处存放我们拥有的开放式支架.由于x3没有本地,我们可能会使用attribute(x3::_val).

x3::rule<struct idBlock2, char> const ruleBlock2{"Block2"};
auto const ruleBlock2_def = x3::rule<struct _, char>{} =
    (
        x3::lit('{')[([](auto& ctx){x3::_val(ctx)='}';})] |
        x3::lit('[')[([](auto& ctx){x3::_val(ctx)=']';})]
    ) …
Run Code Online (Sandbox Code Playgroud)

c++ recursion boost boost-spirit boost-spirit-x3

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