简体   繁体   中英

Perfect forwarding of variadic template templates

I'm currently playing around with some of the new C++17 features, specifically std::optional , and I decided I'd have a go at coming up with a minimum-finding function using variadic template templates. This is what I have so far:

template <template <typename> typename Opt, 
          typename T>
Opt<T> optional_min(Opt<T>&& opt) {
    return std::forward<Opt<T>>(opt);
}

template <template <typename> typename Opt0,
          template <typename> typename Opt1,
          template <typename> typename... Opts, typename T >
std::common_type_t<Opt0<T>, Opt1<T>, Opts<T>...> 
optional_min(Opt0<T>&& opt0, Opt1<T>&& opt1, Opts<T>&&... opts) {
    if (!opt0 && !opt1) 
    {
        return optional_min(std::optional<T>(std::nullopt), std::forward<Opts<T>>(opts)...);
    } 
    else if (opt0 && !opt1) 
    {
        return optional_min(opt0, std::forward<Opts<T>>(opts)...);
    } 
    else if (!opt0 && opt1) 
    {
        return optional_min(opt1, std::forward<Opts<T>>(opts)...);
    } 
    else 
    {
        return (*opt0 < *opt1) ? 
            optional_min(opt0, std::forward<Opts<T>>(opts)...) 
                : optional_min(opt1, std::forward<Opts<T>>(opts)...);
    }
}

int main() {
    std::optional<int> a = 9;
    std::optional<int> b = std::nullopt;
    std::optional<int> c = 4;

    if (auto x = optional_min(a, b, c)) 
        std::cout << *x << std::endl;

    return 0;
}

It seems like my forwarding isn't working. I'm still new to the idea of forwarding, so I could just be missing something silly. The error I get is this:

error: no matching function for call to 'optional_min(std::optional<int>&, std::optional<int>&, std::optional<int>&)'

error: cannot bind rvalue reference of type 'std::optional<int>&' to lvalue of type 'std::optional<int>'
  auto x = optional_min(a, b, c);

My compiler is also telling me that my variadic optional_min function is only a close match, and that it's trying to match my other optional_min function, that one that only takes in one argument. Does anyone know why this might be the case? Please let me know if you need to know a little more.

None of optional_min 's parameters are forwarding references. They are all rvalue references.

Forwarding references are formed when you declare a parameter to be an rvalue reference to a deduced template type parameter, but that's not the case here. optional_min 's parameters are rvalue references to instantiations of deduced template template parameters.

To avoid this, just get rid of the Opt0 , Opt1 and Opts template template parameters, and use type parameters directly:

template <typename Opt0, typename Opt1, typename... Opts>
auto optional_min(Opt0&& opt0, Opt1&& opt1, Opts&&... opts) {
    //...
}

You could use SFINAE to limit the type parameters to instantiations of std::optional if that's your goal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM