I am trying to write a class that uses a std::tuple
to store a bunch of objects with potentially different types. If the elements all have ctors that take some parameter, I can initialize the tuple from the container’s ctor correctly. However, if one of the elements only has a default ctor and the others do not, I am unable to construct the tuple. I get a compilation error.
Here’s the code:
<code>struct Op1WithArg
{
Op1WithArg(int){}
};
struct Op2WithArg
{
Op2WithArg(std::string){}
};
struct OpWithoutArg
{
OpWithoutArg(){}
};
template <class... Ops>
struct OpsSequence {
using OpTuple = std::tuple<Ops...>;
template<typename... Args>
OpsSequence(Args... args)
: mOps{args...}
{}
OpTuple mOps;
};
void TestSequenceWithOpWithoutArg()
{
// This works
using SequenceType = OpsSequence<OpWithoutArg>;
SequenceType sequence{};
}
void TestSequenceWithTwoOpsWithArg()
{
// This works
using SequenceType = OpsSequence<Op1WithArg, Op2WithArg>;
SequenceType sequence{1, "Hello"};
}
void TestSequenceWithOneOpWithArgAndOneWithout()
{
// This fails to compile
using SequenceType = OpsSequence<Op1WithArg, OpWithoutArg>;
SequenceType sequence{1,{}};
}
</code>
<code>struct Op1WithArg
{
Op1WithArg(int){}
};
struct Op2WithArg
{
Op2WithArg(std::string){}
};
struct OpWithoutArg
{
OpWithoutArg(){}
};
template <class... Ops>
struct OpsSequence {
using OpTuple = std::tuple<Ops...>;
template<typename... Args>
OpsSequence(Args... args)
: mOps{args...}
{}
OpTuple mOps;
};
void TestSequenceWithOpWithoutArg()
{
// This works
using SequenceType = OpsSequence<OpWithoutArg>;
SequenceType sequence{};
}
void TestSequenceWithTwoOpsWithArg()
{
// This works
using SequenceType = OpsSequence<Op1WithArg, Op2WithArg>;
SequenceType sequence{1, "Hello"};
}
void TestSequenceWithOneOpWithArgAndOneWithout()
{
// This fails to compile
using SequenceType = OpsSequence<Op1WithArg, OpWithoutArg>;
SequenceType sequence{1,{}};
}
</code>
struct Op1WithArg
{
Op1WithArg(int){}
};
struct Op2WithArg
{
Op2WithArg(std::string){}
};
struct OpWithoutArg
{
OpWithoutArg(){}
};
template <class... Ops>
struct OpsSequence {
using OpTuple = std::tuple<Ops...>;
template<typename... Args>
OpsSequence(Args... args)
: mOps{args...}
{}
OpTuple mOps;
};
void TestSequenceWithOpWithoutArg()
{
// This works
using SequenceType = OpsSequence<OpWithoutArg>;
SequenceType sequence{};
}
void TestSequenceWithTwoOpsWithArg()
{
// This works
using SequenceType = OpsSequence<Op1WithArg, Op2WithArg>;
SequenceType sequence{1, "Hello"};
}
void TestSequenceWithOneOpWithArgAndOneWithout()
{
// This fails to compile
using SequenceType = OpsSequence<Op1WithArg, OpWithoutArg>;
SequenceType sequence{1,{}};
}
The compilation failure for the final function is as follows:
<code>|| [ 50%] Building CXX object CMakeFiles/tsconv_tests.dir/tests/tsconv_tests.cpp.o
|| /home/anders/src/tsconv/tests/tsconv_tests.cpp: In function ‘void tsconv::TestSequenceWithOneOpWithArgAndOneWithout()’:
tests/tsconv_tests.cpp|1014 col 31| error: no matching function for call to ‘tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(<brace-enclosed initializer list>)’
|| 1014 | SequenceType sequence{1,{}};
|| | ^
tests/tsconv_tests.cpp|989 col 5| note: candidate: ‘tsconv::OpsSequence<Ops>::OpsSequence(Args ...) [with Args = {}; Ops = {tsconv::Op1WithArg, tsconv::OpWithoutArg}]’
|| 989 | OpsSequence(Args... args)
|| | ^~~~~~~~~~~
tests/tsconv_tests.cpp|989 col 5| note: candidate expects 0 arguments, 2 provided
tests/tsconv_tests.cpp|985 col 8| note: candidate: ‘constexpr tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(const tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>&)’
|| 985 | struct OpsSequence {
|| | ^~~~~~~~~~~
tests/tsconv_tests.cpp|985 col 8| note: candidate expects 1 argument, 2 provided
tests/tsconv_tests.cpp|985 col 8| note: candidate: ‘constexpr tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>&&)’
tests/tsconv_tests.cpp|985 col 8| note: candidate expects 1 argument, 2 provided
gmake[2]: *** [CMakeFiles/tsconv_tests.dir/build.make|76| CMakeFiles/tsconv_tests.dir/tests/tsconv_tests.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2|83| CMakeFiles/tsconv_tests.dir/all] Error 2
gmake: *** [Makefile|101| all] Error 2
</code>
<code>|| [ 50%] Building CXX object CMakeFiles/tsconv_tests.dir/tests/tsconv_tests.cpp.o
|| /home/anders/src/tsconv/tests/tsconv_tests.cpp: In function ‘void tsconv::TestSequenceWithOneOpWithArgAndOneWithout()’:
tests/tsconv_tests.cpp|1014 col 31| error: no matching function for call to ‘tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(<brace-enclosed initializer list>)’
|| 1014 | SequenceType sequence{1,{}};
|| | ^
tests/tsconv_tests.cpp|989 col 5| note: candidate: ‘tsconv::OpsSequence<Ops>::OpsSequence(Args ...) [with Args = {}; Ops = {tsconv::Op1WithArg, tsconv::OpWithoutArg}]’
|| 989 | OpsSequence(Args... args)
|| | ^~~~~~~~~~~
tests/tsconv_tests.cpp|989 col 5| note: candidate expects 0 arguments, 2 provided
tests/tsconv_tests.cpp|985 col 8| note: candidate: ‘constexpr tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(const tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>&)’
|| 985 | struct OpsSequence {
|| | ^~~~~~~~~~~
tests/tsconv_tests.cpp|985 col 8| note: candidate expects 1 argument, 2 provided
tests/tsconv_tests.cpp|985 col 8| note: candidate: ‘constexpr tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>&&)’
tests/tsconv_tests.cpp|985 col 8| note: candidate expects 1 argument, 2 provided
gmake[2]: *** [CMakeFiles/tsconv_tests.dir/build.make|76| CMakeFiles/tsconv_tests.dir/tests/tsconv_tests.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2|83| CMakeFiles/tsconv_tests.dir/all] Error 2
gmake: *** [Makefile|101| all] Error 2
</code>
|| [ 50%] Building CXX object CMakeFiles/tsconv_tests.dir/tests/tsconv_tests.cpp.o
|| /home/anders/src/tsconv/tests/tsconv_tests.cpp: In function ‘void tsconv::TestSequenceWithOneOpWithArgAndOneWithout()’:
tests/tsconv_tests.cpp|1014 col 31| error: no matching function for call to ‘tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(<brace-enclosed initializer list>)’
|| 1014 | SequenceType sequence{1,{}};
|| | ^
tests/tsconv_tests.cpp|989 col 5| note: candidate: ‘tsconv::OpsSequence<Ops>::OpsSequence(Args ...) [with Args = {}; Ops = {tsconv::Op1WithArg, tsconv::OpWithoutArg}]’
|| 989 | OpsSequence(Args... args)
|| | ^~~~~~~~~~~
tests/tsconv_tests.cpp|989 col 5| note: candidate expects 0 arguments, 2 provided
tests/tsconv_tests.cpp|985 col 8| note: candidate: ‘constexpr tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(const tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>&)’
|| 985 | struct OpsSequence {
|| | ^~~~~~~~~~~
tests/tsconv_tests.cpp|985 col 8| note: candidate expects 1 argument, 2 provided
tests/tsconv_tests.cpp|985 col 8| note: candidate: ‘constexpr tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>::OpsSequence(tsconv::OpsSequence<tsconv::Op1WithArg, tsconv::OpWithoutArg>&&)’
tests/tsconv_tests.cpp|985 col 8| note: candidate expects 1 argument, 2 provided
gmake[2]: *** [CMakeFiles/tsconv_tests.dir/build.make|76| CMakeFiles/tsconv_tests.dir/tests/tsconv_tests.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2|83| CMakeFiles/tsconv_tests.dir/all] Error 2
gmake: *** [Makefile|101| all] Error 2
Is it possible to modify the code to get the failing function to compile?