MooMoo
MooMoo

Reputation: 1116

Avoid Conversion from single element vector to primitive type

I have a problem with constant single element std::vector when pass through a function. C++ compiler automatically call wrong function when the std::vector variable contain a single element. This is though the policy of C++ design. However is there any explicit method to specify in such a case. Here are the examples of the problems

assume i have two overload functions both have the same name "foo"

void foo(const std::vector<int> A)
{
         // do vector operator
     printf("vector thing");
}


void foo(int a)
{
     // do integer operator
     printf("integer thing")
}

In general case both of these functions are called correctly

foo({1,2,3});    // print do vector thing
foo( 3 );        // print do integer thing

however from c++ rule. when call

foo({5});        // print do integer thing ( I want it to call as vector )

one of the methods is to create a variable

std::vector<int> B = { 5 };

in order to solve this problem.

I feel this method is a bit clumsy. Is there any method that can void the compiler to treat {5} as 5 and call foo(int a).

note: here is the reference that explain what the problem is c++11 single element vector initialization in a function call

Upvotes: 3

Views: 79

Answers (3)

lubgr
lubgr

Reputation: 38315

One way to disambiguate the function call is to make the integer overload a function template:

template <class Int> void foo(Int a)
{
   std::printf("generalized (maybe integer) thing\n");
}

This way, the invocation

foo({3});

will consider the non-templated function a better match while foo(3) instantiates and calls the function template. This because {3} is an std::initializer_list<int> with one element in the context of type deduction. You can also redirect to the original foo(int a) function like this:

void fooImpl(int a)
{
   std::printf("integer thing\n");
}

template <class Int> void foo(Int&& a)
{
   fooImpl(std::forward<Int>(a));
}

This refuses to compile when e.g. calling foo with an argument not convertible to an integer, which might be a desirable usage restriction. Also, it should be very unlikely that you encounter a performance overhead due to the forwarding intermediate function.

Upvotes: 3

HolyBlackCat
HolyBlackCat

Reputation: 96791

You need another overload, taking std::initializer_list as a parameter:

void foo(std::initializer_list<int> A)
{
    foo(std::vector<int>(A.begin(), A.end()));
}

If you always call this function by creating vectors directly with {...}, rather than using std::vector variables, then you can remove std::vector overload completely and operate directly on std::initializer_list.

Upvotes: 6

Paulo Pinto
Paulo Pinto

Reputation: 622

No, because as of C++17 the rules explained on the linked answer still hold.

You can create a temporary instead of a variable, though.

foo(std::vector{5});      // C++17 with class type deduction
foo(std::vector<int>{5}); // older versions

Upvotes: 5

Related Questions