Perfect redirection, variation pattern, initializer_list - together

gcc 4.8.1 and clang 3.3, C ++ 11 is complete, I need to move args to some function that creates elements like make_shared / C ++ 14 make_unique. But I have a problem with subtract / forward types of initializer / array lists

I need a working example foo * foo3{ make_it<foo>( {{1,1},{ 10,10 }}, 10 ) }; , so std::initializer_list will output its arguments and the function will redirect 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; } 

foo3 will actually 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 
+4
source share
2 answers

Unified initialization does not work with forwarding. You cannot redirect initialization parameters (directly), and then use them to initialize any object. You can initialize a function parameter and then forward it to someone else, but you cannot forward initialization parameters.

Brand-init-lists (aka: the {} ) are not involved in the output of the template argument. This is why your foo3 gets an error when you do this. The compiler cannot know what type you want to convert, so it fails.

Even if you tried to save {{1, 1}, {10, 10}} in the auto variable, you won’t get what you want. auto can parenthesize init-lists in the initializer_list types, but you get something like initializer_list<initializer_list<int>> .

The compiler simply will not go through your template code and figure out what type you really had in mind.

+4
source

Is a solution that works only for foo::pairs lists acceptable?

 template<typename ValueType, typename... Args> ValueType * make_it(std::initializer_list<foo::pairs> il, Args&&... args) { ValueType * obj = new (allocfromstore(sizeof(ValueType))) ValueType( il, std::forward<Args>(args)...); return obj; } 
+1
source

Source: https://habr.com/ru/post/1494801/


All Articles