小编Hol*_*Cat的帖子

在自己的成员函数中构造类时,如何强制类模板参数推导?

考虑以下代码:

struct A {};

template <typename T> struct B
{
    B(T) {}
    auto foo() {return B(A{});} // error: no matching function for call to 'B<int>::B(A)'
};

auto foo() {return B(A{});} // compiles

int main()
{
    foo();
    B b(0);
    b.foo();
}
Run Code Online (Sandbox Code Playgroud)

Try it live

我理解为什么B::foo()不编译:内部struct B<T>,B(作为注入类名称)意味着B<T>除非它被明确地用作模板.在这种情况下,这会阻止类模板参数推断.

假设我不能这样做,auto foo() {return B<A>(A{});}因为我的实际代码依赖于用户提供的略微复杂的演绎指南.

问题是:在构造B内部时如何强制类模板参数推导B::foo

我希望我不会错过一些明显的东西.

c++ c++17

11
推荐指数
1
解决办法
161
查看次数

`std::variant` 的重载 &amp;&amp; 会破坏不相关的 `std::map`

(这个问题最初是由俄罗斯 SO的另一位用户提出的。我在此处重新发布并稍作更改,以增加曝光率。)

考虑这个代码:

#include <map>
#include <variant>

void operator&&(std::variant<int>, std::variant<int>) {}

int main()
{
    std::map<int, int> vals;
    vals.find(42);
}
Run Code Online (Sandbox Code Playgroud)

Clang(使用 libstdc++ 和 libc++)和 MSVC 编译它没有问题。

Hovewer、GCC 11.1 和更新版本(包括主干)给出了这个: Run on gcc.godbolt.org

#include <map>
#include <variant>

void operator&&(std::variant<int>, std::variant<int>) {}

int main()
{
    std::map<int, int> vals;
    vals.find(42);
}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?


编辑:

我们的operator==重载对于名称查找应该是不可见的<variant>(除了 ADL,这里不涉及),所以这绝对是一个 GCC 错误。

@rustyx 发现GCC 错误 #51577,看起来非常相似。但是还有更多,因为该错误是在 GCC 4.7.0 中引入的,而上面的代码仅在 11.1 和更新版本中出现。

c++ gcc

11
推荐指数
1
解决办法
266
查看次数

使用联盟的一个字段的地址来访问另一个字段是否合法?

考虑以下代码:

union U
{
    int a;
    float b;
};

int main()
{
    U u;
    int *p = &u.a;
    *(float *)p = 1.0f; // <-- this line
}
Run Code Online (Sandbox Code Playgroud)

我们都知道联合字段的地址通常是相同的,但是我不确定它是否是定义良好的行为来做这样的事情.

因此,问题是:在上面的代码中,如何转换和取消引用指向union字段的指针是合法且定义明确的行为吗?


PS我知道它比C++更多C,但我试图理解它是否在C++中是合法的,而不是C.

c++

10
推荐指数
1
解决办法
922
查看次数

co_yield 指向局部协程变量的指针是否不安全?

众所周知,返回指向堆栈变量的指针通常是一个坏主意:

int* foo() {
  int i = 0;
  return &i;
}

int main() {
  int* p = foo();
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,我的理解是 被int破坏了,p悬空指针也被破坏了。

我想知道这在多大程度上适用于 C++20 新引入的协程:

generator<span<byte>> read(stream& s) {
  array<byte, 4096> b;
  while (s.is_open()) {
    const size_t n = s.read_some(b);
    co_yield span(b, n);
  }
}

int main() {
  stream s;
  for (span<byte> v : read(s)) {
    /* ... */
  }
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,read协程生成span本地缓冲区的视图b。在内部,该视图存储一个指向缓冲区的指针。v当与范围循环体一起使用时,该指针是否会悬空for

对于上下文,第二个示例中的协程代码是根据我自己的项目中的代码建模的。在那里,AddressSanitizer 以“释放后使用”错误结束程序。通常我认为这足以回答我的问题,但由于此时协程开发仍在进行中(我的项目正在使用boost::asio::experimental::coro,强调“实验”),我想知道该错误是否是由以下错误引起的generator …

c++ coroutine dangling-pointer c++20 c++-coroutine

10
推荐指数
1
解决办法
244
查看次数

表达式到底是什么?

考虑x声明中是否int x;有表达式。

我以前以为肯定不是,但是语法id-expression这里把变量名称为an。

那么有人可能会争辩说 onlyexpression是一个表达式,而不是??-expression。但在 中1 + 2,既不匹配1也不2匹配,因为它们分别是additive-expressionmultiplicative-expression,而不是expressions。但常识告诉我们,这些也应该被称为表达式。

我们可以决定any ??-expression(包括expression)是一个表达式,但声明中的变量名也匹配。

我们可以将表达式定义为 any ??-expressionexcept id-expression,但这感觉相当随意。

表达式的正确语法定义是什么?其声明中的变量名是否是表达式?

c++ language-lawyer

10
推荐指数
1
解决办法
427
查看次数

-O1/2/3 with -std = c ++ 1y/11/98 - 如果包含<cmath>我收到错误:'_hypot'未在此范围内声明

我刚刚更新MinGW的使用mingw-get-setup状态,我无法构建一个包含点儿什么<cmath>,如果我使用任何大于头-O0-std=c++1y.(我也试过c++11c++98)我得到象这样的错误之一:

g++.exe -pedantic-errors -pedantic -Wextra -Wall -std=c++1y -O3  -c Z:\Projects\C++\L6\src\events.cpp -o obj\src\events.o
In file included from z:\lander\mingw\lib\gcc\mingw32\4.8.1\include\c++\cmath:44:0,
                 from Z:\Projects\C++\L6\src\utils.h:4,
                 from Z:\Projects\C++\L6\src\events.cpp:10:
z:\lander\mingw\include\math.h: In function 'float hypotf(float, float)':
z:\lander\mingw\include\math.h:635:30: error: '_hypot' was not declared in this scope
 { return (float)(_hypot (x, y)); }
Run Code Online (Sandbox Code Playgroud)

我这边有什么不对劲吗?
或mingw repo的版本被窃听?如果是这样,这个标题有什么快速解决方法吗?

c++ mingw mingw32

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

更好地禁用函数的基于参数的模板参数推导的方法?

这是我想要做的:

template <typename T> void f(DisableDeduction<T> obj) {std::cout << obj;}
// Here DisableDeduction<T> aliases T, but in a such way
// that would prevent compiler from deducing T based
// on provided argument.

/* ... */

f<int>(1); // Works.
f(1); // Error, can't deduce template parameter based on argument.
Run Code Online (Sandbox Code Playgroud)

这就是我目前实现它的方式:

template <typename T> struct DisableDeduction_Internal {using type = T;};
template <typename T> using DisableDeduction = typename DisableDeduction_Internal<T>::type;
Run Code Online (Sandbox Code Playgroud)

它完美地工作(如上所述),但它引入了一个额外的帮助器类型.

但是我可以在没有额外类型的情

c++ templates

9
推荐指数
2
解决办法
725
查看次数

使用MinGW-w64的Clang 8:如何使用地址和UB消毒器?

Clang 8发行说明中有以下内容:

  • 允许在MinGW上使用Address Sanitizer和Undefined Behavior Sanitizer。

但是,我无法弄清楚如何正确使用它们。

我将Clang 8.0.0与MSYS2 MinGW GCC结合使用。确切的细节在问题的底部。

我正在尝试编译以下最少的代码:

1.cpp

#include <iostream>

int main()
{
    // Testing ubsan
    int x = 0x7fffffff;
    x++;
    std::cout << x << std::endl;

    // Testing asan
    int *y = new int;
    delete y;
    std::cout << *y << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

以下是结果-fsanitize=address

# /z/Lander/LLVM/bin/clang++ -target x86_64-w64-windows-gnu -fsanitize=address 1.cpp
Z:\Lander\msys2\mingw64\bin\ld.exe: cannot find Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\libclang_rt.asan_dynamic-x86_64.dll.a: No such file or directory
Z:\Lander\msys2\mingw64\bin\ld.exe: cannot find Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\libclang_rt.asan_dynamic_runtime_thunk-x86_64.a: No such file or directory
Z:\Lander\msys2\mingw64\bin\ld.exe: cannot find Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\libclang_rt.asan_dynamic_runtime_thunk-x86_64.a: No …
Run Code Online (Sandbox Code Playgroud)

c++ clang mingw-w64 address-sanitizer ubsan

9
推荐指数
2
解决办法
495
查看次数

通过将对象指针转换为`char *`,然后执行`*(member_type*)(pointer + offset)`来访问成员是否是UB?

下面是一个例子:

#include <cstddef>
#include <iostream>

struct A
{
    char padding[7];
    int x;
};
constexpr int offset = offsetof(A, x);

int main()
{
    A a;
    a.x = 42;
    char *ptr = (char *)&a;
    std::cout << *(int *)(ptr + offset) << '\n'; // Well-defined or not?
}
Run Code Online (Sandbox Code Playgroud)

我一直认为它是明确定义的(否则有什么意义offsetof),但不确定。

最近有人告诉我它实际上是UB,所以我想一劳永逸地弄清楚。

上面的例子是否会导致UB?如果将类修改为非标准布局,是否会影响结果?

如果是 UB,是否有任何解决方法(例如申请std::launder)?


整个主题似乎都没有实际意义且没有具体说明。

以下是我能找到的一些信息:

c++ language-lawyer

9
推荐指数
2
解决办法
378
查看次数

C++20 中模板对非类型文字参数的部分特化:clang 和 gcc 不同意

在 c++20 中玩弄文字、非类型模板参数,我发现 g++ 和 clang++ 不同意以下代码。

#include <algorithm>

template<size_t N>
struct StringLiteral {
    constexpr StringLiteral(const char (&str)[N]) {
        std::copy_n(str, N, value);
    }
    char value[N];
};

template <typename T, StringLiteral Name>
struct named{};

template <typename T>
struct is_named: std::false_type{};

template <typename T, size_t N, StringLiteral<N> Name>
struct is_named<named<T, Name>>: std::true_type{};

// This will fail with g++
static_assert(is_named<named<int, "ciao">>::value == true);
Run Code Online (Sandbox Code Playgroud)

在 Godbolt 上实时查看:https ://godbolt.org/z/f3afjd

首先也是最重要的,我什至不确定我是否以正确的方式做这件事:它是与泛型StringLiteral<N>类型匹配的方式,还是不是?如果不是,正确的方法是什么?

而且,为什么编译器不同意呢?谁有错误?


编辑:发现删除size_t N部分特化中的参数使两个编译器都同意,结果是预期的。像这样:

template <typename T, StringLiteral …
Run Code Online (Sandbox Code Playgroud)

c++ g++ language-lawyer clang++ c++20

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