2
#include <utility>
#include <iostream>

struct Data {
    uint8_t m_x;
    double m_y;
    uint32_t m_z;
    Data(uint8_t x, double y, uint32_t z) : m_x(x), m_y(y), m_z(z) {
        std::cout << "constructor called" << std::endl;
    }
};

template <class Data, typename... Args>
class Layer1 {
public:
    void foo(Args&&... args) {
        Data(std::forward(args)...);
    }
};

int main() {
    Layer1<Data, uint8_t, double, uint32_t> layer1;
    layer1.foo(1, 1.1, 2);
}

When I compile the code above, gcc 8.2 outputs:

$ g++ -Wall test_forward.cpp -o test_forward -O3 -std=c++17
test_forward.cpp: In instantiation of ‘void Layer1<Data, Args>::foo(Args&& ...) [with Data = Data; Args = {unsigned char, double, unsigned int}]’:
test_forward.cpp:39:22:   required from here
test_forward.cpp:31:16: warning: unused variable ‘layer2’ [-Wunused-variable]
   Layer2<Data> layer2;
                ^~~~~~
[hchan@heilinux cpp]$ g++ -Wall test_forward.cpp -o test_forward -O3 -std=c++17
[hchan@heilinux cpp]$ g++ -Wall test_forward.cpp -o test_forward -O3 -std=c++17
test_forward.cpp: In instantiation of ‘Layer1<Data, Args>::MyData::MyData(Args&& ...) [with Data = Data; Args = {unsigned char, double, unsigned int}]’:
test_forward.cpp:32:3:   required from ‘void Layer1<Data, Args>::foo(Args&& ...) [with Data = Data; Args = {unsigned char, double, unsigned int}]’
test_forward.cpp:39:22:   required from here
test_forward.cpp:27:51: error: no matching function for call to ‘forward(unsigned char&)’
   MyData(Args&&... args) : i(0), data(std::forward(args)...) {}
                                       ~~~~~~~~~~~~^~~~~~
In file included from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/stl_pair.h:59,
                 from /opt/rh/devtoolset-8/root/usr/include/c++/8/utility:70,
                 from test_forward.cpp:1:
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:74:5: note: candidate: ‘template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_Tp>::type&)’
     forward(typename std::remove_reference<_Tp>::type& __t) noexcept
     ^~~~~~~
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:74:5: note:   template argument deduction/substitution failed:
test_forward.cpp:27:51: note:   couldn't deduce template parameter ‘_Tp’
   MyData(Args&&... args) : i(0), data(std::forward(args)...) {}
                                       ~~~~~~~~~~~~^~~~~~
In file included from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/stl_pair.h:59,
                 from /opt/rh/devtoolset-8/root/usr/include/c++/8/utility:70,
                 from test_forward.cpp:1:
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:85:5: note: candidate: ‘template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_Tp>::type&&)’
     forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
     ^~~~~~~
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:85:5: note:   template argument deduction/substitution failed:
test_forward.cpp:27:51: note:   couldn't deduce template parameter ‘_Tp’
   MyData(Args&&... args) : i(0), data(std::forward(args)...) {}
                                       ~~~~~~~~~~~~^~~~~~
[hchan@heilinux cpp]$ g++ -Wall test_forward.cpp -o test_forward -O3 -std=c++17
[hchan@heilinux cpp]$ 
[hchan@heilinux cpp]$ 
[hchan@heilinux cpp]$ 
[hchan@heilinux cpp]$ g++ -Wall test_forward.cpp -o test_forward -O3 -std=c++17
test_forward.cpp: In instantiation of ‘void Layer1<Data, Args>::foo(Args&& ...) [with Data = Data; Args = {unsigned char, double, unsigned int}]’:
test_forward.cpp:23:22:   required from here
test_forward.cpp:17:20: error: no matching function for call to ‘forward(unsigned char&)’
   Data(std::forward(args)...);
        ~~~~~~~~~~~~^~~~~~
In file included from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/stl_pair.h:59,
                 from /opt/rh/devtoolset-8/root/usr/include/c++/8/utility:70,
                 from test_forward.cpp:1:
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:74:5: note: candidate: ‘template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_Tp>::type&)’
     forward(typename std::remove_reference<_Tp>::type& __t) noexcept
     ^~~~~~~
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:74:5: note:   template argument deduction/substitution failed:
test_forward.cpp:17:20: note:   couldn't deduce template parameter ‘_Tp’
   Data(std::forward(args)...);
        ~~~~~~~~~~~~^~~~~~
In file included from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/stl_pair.h:59,
                 from /opt/rh/devtoolset-8/root/usr/include/c++/8/utility:70,
                 from test_forward.cpp:1:
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:85:5: note: candidate: ‘template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_Tp>::type&&)’
     forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
     ^~~~~~~
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/move.h:85:5: note:   template argument deduction/substitution failed:
test_forward.cpp:17:20: note:   couldn't deduce template parameter ‘_Tp’
   Data(std::forward(args)...);
        ~~~~~~~~~~~~^~~~~~

For some reason, it seems like the template deduction fails. If I change Data(std::forward(args)...) to Data(std::forward<Args>(args)...), it works.

I wonder why compiler fails to deduce the argument types and what compiler is actually thinking of the type (i.e. no matching function for call to ‘forward(unsigned char&)’).

Basically, I am trying understand why more hint is needed (i.e. explicitly states <Args>).

Thanks!

HCSF
  • 2,387
  • 1
  • 14
  • 40

0 Answers0