Constructing a non-copyable, non-movable type into a function parameter without invoking initializer_list constructor

StackOverflow https://stackoverflow.com/questions/22621786

  •  20-06-2023
  •  | 
  •  

Question

#include <initializer_list>
#include <iostream>

namespace {

class C {
public:
    C(C const &) = delete;
    C(C &&) = delete;
    C(int) {
        std::cout << "int\n";
    }
    C(std::initializer_list<int>) {
        std::cout << "initializer\n";
    }
};

void f(C) {
}

// Compiles and prints "initializer" when called
C g() { return {0}; }
// Fails to compile
// C h() { return 0; }

}   // namespace

int main() {
    // Compiles and prints "initializer"
    f({0});
    // Fails to compile
    // f(0);
}

Is it possible to construct C, a non-copyable, non-movable type, into a function parameter or function return value without invoking the initializer_list constructor?

Was it helpful?

Solution

It's only possible if you can change C so the desired constructor can be chosen instead of the initializer-list constructor, e.g. by wrapping the argument type in something that isn't convertible to the element type of the initializer-list constructor:

#include <initializer_list>
#include <iostream>

namespace {

template<class T>
struct wrap
{
  T value;
};

class C {
public:
    C(C const &) = delete;
    C(C &&) = delete;
    C(wrap<int>) {
        std::cout << "int\n";
    }
    C(std::initializer_list<int>) {
        std::cout << "initializer\n";
    }
};

void f(C) {
}

// Compiles and prints "int" when called
C g() { return {wrap<int>{0}}; }

}   // namespace

int main() {
    // Compiles and prints "int"
    f({wrap<int>{0}});
    g();
}

This prints:

int
int
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top