static_assert 在宏内部抛出编译时错误,即使它不应该抛出 (Visual Studio)

static_assert inside a macro throwing compile time errors even when it shouldn't (Visual Studio)

tl;博士

当我尝试编译此代码时,Visual Studio 为非常 static_assert 抛出一个编译时错误,无论它是否应该,然后还有一个“活动错误”是唯一一个应该。这是我的代码或 Visual Studio?

的问题

Visual Studio版本
微软 Visual Studio 社区 2019
版本 16.10.2

#include <memory>

struct Node {};
struct A : Node {};
struct B : Node {};

#define cast_to_A(ptr) ([&] () { \
    static_assert( \
        std::is_same<std::shared_ptr<Node>, decltype(ptr)>::value, \
        "Cannot cast to an A pointer." \
    ); \
    return std::static_pointer_cast<A>(ptr); \
})()

#define cast_to_B(ptr) ([&] () { \
    static_assert( \
        std::is_same<std::shared_ptr<Node>, decltype(ptr)>::value, \
        "Cannot cast to a B pointer." \
    ); \
    return std::static_pointer_cast<B>(ptr); \
})()

int main() {
    auto a = std::make_shared<A>();
    auto b = std::make_shared<B>();
    auto aAsNode = std::static_pointer_cast<Node>(a);
    auto bAsNode = std::static_pointer_cast<Node>(b);

    auto a1 = cast_to_A(aAsNode); // Expected: No error, Actual: "Cannot cast to an A pointer."
    auto b1 = cast_to_B(bAsNode); // Expected: No error, Actual: "Cannot cast to an B pointer."

    auto badCast = cast_to_A(b); // Expected & Actual: "Cannot cast to an A pointer."

    return 0;
}

上下文

在个人项目中,我有一个 node 结构,一堆子结构继承自该结构。在整个程序中,我使用 std::static_pointer_caststd::shared_ptr<Node> 转换为 std::shared_ptr<Child>,反之亦然。在我的程序中的某个地方,我有编译时错误,我正在尝试从一个同级指针转换为另一个。但是,该错误归因于 std::static_pointer_cast 中的代码( 的第 1925 行),并且由于它不是运行时错误,所以我无法向上移动调用堆栈以查找我的错误调用所在的位置。

碰巧,我的结构代码是由我编写的 python 脚本程序生成的。我尝试的解决方案是为每个结构生成一个宏(就像在玩具示例中看到的那样),然后我只是做了一个正则表达式 search/replace 来用适当的宏替换我所有的 std::static_pointer_cast 调用。

我遇到的问题是在上面的玩具示例中重新创建的。 Visual Studio 在我预计会失败的宏“调用”下面放了一条红线(所以我现在实际上已经找到了这个错误),但是对于每次使用宏,它也会从static_assert,即使(据我所知)它不应该失败。不过,它并没有在那些“电话”下面放一条红线,所以我不确定这是否是一个 Visual Studio 错误。

上网查了一下,发现std::is_same对于什么算同类型还是非常讲究的。作为 marco 参数给出的变量通过引用传递给 static_assert(因为它通过 lambda 的 [&] 捕获),所以我想知道这是否将其丢弃。但是我想不出任何方法来调整类型以使其工作。

在此先感谢您的帮助!非常感谢任何指示或提示!

@1201ProgramAlarm 在评论中回答。解决方案是使用 std::remove_reference 删除传递给 lambda 时添加到 ptr 的引用。最后的宏是:

#define cast_to_A(ptr) ([&] () { \
    static_assert( \
        std::is_same<std::shared_ptr<Node>, std::remove_reference<decltype(ptr)>::type>::value, \
        "Cannot cast to an A pointer." \
    ); \
    return std::static_pointer_cast<A>(ptr); \
})()

现在只有预期的“坏演员”会抛出错误