Reputation: 1116
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
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
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
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