gcc 4.8.1 & clang 3.3, c++11 feature complete, I need to forward args in some function that constructs elements like make_shared/c++14 make_unique. But I have problem with type deduction/forwarding initializer lists/arrays
I need working example of foo * foo3{ make_it<foo>( {{1,1},{ 10,10 }}, 10 ) };
, so std::initializer_list
will deduce it arguments and function will forward them
#include <initializer_list>
#include <algorithm>
struct foo
{
struct pairs{ int a,b; };
foo( int value ){}
foo( std::initializer_list<pairs> elems, int value ){}
};
//some custom allocation mechanizm
char store[sizeof(foo)*2];
char * store_ptr = &store[0];
void * allocfromstore( size_t sz ) { void * ret = store_ptr; store_ptr+= sz; return ret; }
template<typename ValueType, typename ArrType, typename... Args>
ValueType * make_it(std::initializer_list<ArrType> il, Args&&... args)
{
ValueType * obj = new (allocfromstore(sizeof(ValueType))) ValueType( il, std::forward<Args>(args)...);
return obj;
}
template<typename ValueType, typename... Args>
ValueType * make_it(Args&&... args)
{
ValueType * obj = new (allocfromstore(sizeof(ValueType))) ValueType( std::forward<Args>(args)...);
return obj;
}
std::initializer_list<foo::pairs> encapsulate( std::initializer_list<foo::pairs> il ){ return il; }
int main(){
foo * foo0{ make_it<foo>( 10 ) };
foo * foo1{ make_it<foo>( std::initializer_list<foo::pairs>({{1,1},{ 10,10 }}), 10 ) };
foo * foo2{ make_it<foo>( encapsulate({{1,1},{ 10,10 }}), 10 ) };
foo * foo3{ make_it<foo>( {{1,1},{ 10,10 }}, 10 ) };
return 0;
}
actually foo3 will fail with clang 3.3:
test.cpp:37:15: error: no matching function for call to 'make_it'
foo * foo3{ make_it<foo>( {{1,1},{ 10,10 }}, 10 ) };
^~~~~~~~~~~~
test.cpp:18:13: note: candidate template ignored: couldn't infer template argument 'ArrType'
ValueType * make_it(std::initializer_list<ArrType> il, Args&&... args)
^
test.cpp:26:13: note: candidate function not viable: requires 0 arguments, but 2 were provided
ValueType * make_it(Args&&... args)
^
1 error generated.
and with gcc 4.8.1:
test.cpp: In function ‘int main()’:
test.cpp:37:51: error: no matching function for call to ‘make_it(<brace-enclosed initializer list>, int)’
foo * foo3{ make_it<foo>( {{1,1},{ 10,10 }}, 10 ) };
^
test.cpp:37:51: note: candidates are:
test.cpp:18:13: note: template<class ValueType, class ArrType, class ... Args> ValueType* make_it(std::initializer_list<ArrType>, Args&& ...)
ValueType * make_it(std::initializer_list<ArrType> il, Args&&... args)
^
test.cpp:18:13: note: template argument deduction/substitution failed:
test.cpp:37:51: note: couldn't deduce template parameter ‘ArrType’
foo * foo3{ make_it<foo>( {{1,1},{ 10,10 }}, 10 ) };
^
test.cpp:26:13: note: ValueType* make_it(Args&& ...) [with ValueType = foo; Args = {}]
ValueType * make_it(Args&&... args)
^
test.cpp:26:13: note: candidate expects 0 arguments, 2 provided
Uniform initialization does not work with forwarding. You can't forward initialization parameters (directly) and then use those to initialize some object. You can initialize a parameter of a function and then forward that along to someone else, but you can't forward initialization parameters.
Braced-init-lists (aka: the {}
stuff) do not participate in template argument deduction. That's why your foo3
gets an error when you do it. The compiler can't know what type you want it converted into, so it fails.
Even if you tried to store {{1, 1}, {10, 10}}
in an auto
variable, you wouldn't get what you want. auto
can type-deduce braced-init-lists into initializer_list
types, but you'd get something like initializer_list<initializer_list<int>>
.
The compiler simply is not going to go through your template code and figure out what type you really meant.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With