【问题标题】:How to provide a copy constructor for the overloaded lambda trick如何为重载的 lambda 技巧提供复制构造函数
【发布时间】:2021-02-04 14:29:09
【问题描述】:

我有以下代码,它使用 lambda 扩展了 overload 技巧以接受变体。但是,变体不是示例中的问题。

https://godbolt.org/z/GxhaPr

#include <memory>
#include <variant>
#include <functional>

template <class ...Fs>
struct overload : Fs... {
    template <class ...Ts>
    overload(Ts&& ...ts) : Fs{std::forward<Ts>(ts)}...
    {} 
    using Fs::operator()...;

    template <class ...Vs>
    auto operator()(std::variant<Vs...>&&arg){
        return std::visit(*this,std::forward<decltype(arg)>(arg));
    }

};

template <typename ...Ts>
overload(Ts&&...) -> overload<std::remove_reference_t<Ts>...>;

using Foo = std::variant<int, char*, double,long>;

int main()
{
    
    auto fn = overload(
                [](int x){ return 0;}
                ,[](char * x) {return 1;}
                ,[](double x){ return 2;}
                ,[](long x){ return 3;}
    );

    std::function<int(Foo)> fn2 = overload(
                [&](auto x){return fn(x);}
    );

    //auto ff = fn;
    //std::function<int(Foo)> fn3 = fn;

    auto a = fn2(10);
    auto b = fn2((char *)"10");
    auto c = fn2(10.);

    auto d = fn(10);
    auto e = fn((char *)"10");
    auto f = fn(10.);

    return a+b+c+d+e+f;
}

效果很好。但是如果我取消注释该行

auto ff=fn;

然后代码失败,因为overload 的默认复制构造函数不起作用。可以写一个吗?

【问题讨论】:

    标签: c++ lambda c++17 overloading


    【解决方案1】:

    您的代码无法编译的原因并不是因为overload 的默认复制构造函数不起作用。这是因为模板化的构造函数基本上是一个包罗万象的东西。任何构造函数参数都会匹配它,所以它总是会被调用。

    您可以在 overload 构造函数上使用一些 SFINAE 以确保它不会被调用以进行复制/移动构造:

    template <class ...Fs>
    struct overload : Fs... {
        template <class ...Ts, std::enable_if_t<
            (sizeof...(Ts) == sizeof...(Fs))
            and (std::is_same_v<Fs, std::remove_reference_t<Ts>> && ...)
          , int> = 0>
        overload(Ts&& ...ts) : Fs{std::forward<Ts>(ts)}...
        {} 
        
        // Rest of existing overload code goes here.
    };
    

    请注意,我不确定我在 std::enable_if 中使用的条件是否完全正确,但我认为它们在这里有意义。他们使您的示例编译,所以...

    godbolt 上解决方案代码的链接:https://godbolt.org/z/Tzn9f3

    【讨论】:

    • C++ 语言规范中确实存在一个错误,即移动引用和转发引用的语法相同,并且仅通过类型是模板参数这一因素来区分。如果有&amp;&amp;&amp; 转发引用运算符,则构造函数可以声明为overload(Fs&amp;&amp;&amp;...fs) : Fs{std::forward&lt;Fs&gt;(fs)}...注意使用 Fs 而不是 Ts。考虑到它造成的痛苦,我从来没有真正理解过这种疏忽。
    • 是的,我同意这样的构造函数可以覆盖复制/移动构造函数是非常烦人的行为。或者,他们可以让你总是必须明确地覆盖它们,但我相信这会打开另一个完整的蠕虫罐头:)。
    猜你喜欢
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    相关资源
    最近更新 更多