std::visit 传递指针无法在 clang 13 下编译

std::visit with passing pointer fails to compile under clang 13

以下代码在 x64 msvc x19.30 and gcc 11 but fails to compile under clang 13.0.1 下正确编译:

"error: cannot pass object of non-trivial type 'std::shared_ptr<std::pair<int, std::variant<Struct1, Struct2, UnsupportedStruct>>>' through variadic function;"

有人知道问题出在哪里吗?

以下代码根据传递的对象产生不同的输出:

#include <iostream>
#include <variant>
#include <memory>

struct Struct1{};
struct Struct2{};
struct UnsupportedStruct{};

using VarTypeData = std::variant<Struct1, Struct2, UnsupportedStruct>;
using VarType = std::pair<int, VarTypeData>;

namespace
{
    void print(Struct1&, std::shared_ptr<VarType> v) {std::cout << v->first << ": Struct1\n";}
    void print(Struct2&, std::shared_ptr<VarType> v) {std::cout << v->first << ": Struct2\n";}
    void print(...) {std::cout << "no implementation";}
}

int main()
{
    VarType data1 = std::make_pair(100, UnsupportedStruct{});
    auto pointerData = std::make_shared<VarType>(data1);
    std::visit([&pointerData](auto& c) {print(c, pointerData);}, pointerData->second);
    std::cout << std::endl;
    pointerData->second = Struct1{};

    std::visit([&pointerData](auto& c) {print(c, pointerData);}, pointerData->second);
}

此代码 works fine for clang 取消引用后:

#include <iostream>
#include <variant>
#include <memory>

struct Struct1{};
struct Struct2{};
struct UnsupportedStruct{};

using VarTypeData = std::variant<Struct1, Struct2, UnsupportedStruct>;
using VarType = std::pair<int, VarTypeData>;

namespace
{
    void print(const Struct1&, const VarType& v) {std::cout << v.first << ": Struct1\n";}
    void print(const Struct2&, const VarType& v) {std::cout << v.first << ": Struct2\n";}
    void print(...) {std::cout << "no implementation";}
}

int main()
{
    VarType data1 = std::make_pair(100, UnsupportedStruct{});
    auto pointerData = std::make_shared<VarType>(data1);
    std::visit([&pointerData](auto& c) {print(c, *pointerData);}, pointerData->second);
    std::cout << std::endl;
    pointerData->second = Struct1{};
    
    std::visit([&pointerData](auto& c) {print(c, *pointerData);}, pointerData->second);
}

感谢@康桐薇的解答

此代码不适用于 clang,因为

void print(...) {std::cout << "no implementation";}

: void print(...) is a C function, where variadic actually means the 's parameter. It accepts only trivial types, which std::shared_ptr is not. So the behavior is undefined or only conditionally supported

因此,以下更改fix问题:

template<class... Args> 
    void print(Args&&...) {std::cout << "no implementation";}