Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we keep a redundant ctor in std::copyable_function?

According to the C++ docs, std::copyable_function has two overloaded ctors as follows:

template<class T, class... CArgs>
explicit copyable_function(std::in_place_type_t<T>, 
    CArgs&&... args);

template<class T, class U, class... CArgs>
explicit copyable_function(std::in_place_type_t<T>, 
    std::initializer_list<U> il, CArgs&&... args);

Note that both ctors are required to construct its underlying callable object using direct-non-list-initialization. Consider the following code:

struct Functor {
    Functor(int, int) {
    }

    Functor(std::initializer_list<int>) {
    }

    void operator()() const {
    }
};

std::copyable_function(std::in_place_type<Functor>, 1, 2) will call Functor::Functor(int, int) rather than Functor::Functor(std::initializer_list<int>).

If we want to call Functor::Functor(std::initializer_list<int>), just use std::copyable_function(std::in_place_type<Functor>, std::initializer_list{1, 2}).

Both cases are intuitive and no ambiguity. So, my question is:

Why do we need the second ctor while the first one is enough?

like image 243
xmllmx Avatar asked Dec 02 '25 21:12

xmllmx


1 Answers

{..} has no types and can only be deduced in few cases:

  • std::initializer_list<T>
  • const T(&)[N]

CArgs&& is not one of them so cannot deduce {1, 2} as std::initializer_list<int>

The second overload is needed.

You can see yourself with simplified example:

template <typename T>
void foo(T&&) {}

int main() {
    foo({1, 2}); // Error
}

Demo

like image 141
Jarod42 Avatar answered Dec 05 '25 12:12

Jarod42



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!