我正在尝试编写一个类,它使用
std::tuple
来存储一堆可能具有不同类型的对象。如果元素都具有接受某些参数的构造函数,我可以正确地从容器的构造函数初始化元组。但是,如果其中一个元素只有默认构造函数而其他元素没有,则我无法构造元组。我收到编译错误。
这是代码:
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,{}};
}
最终函数编译失败如下:
|| [ 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
是否可以修改代码来编译失败的函数?
std::piecewise_construct
。
我看到的唯一解决方案是仅使用默认构造函数向类添加虚拟类型。当然,这需要您自己修改类型,而您可能无法做到:
// Dummy tag type
struct DefaultConstructTag {};
struct Op1WithArg
{
Op1WithArg(int){}
};
struct Op2WithArg
{
Op2WithArg(std::string){}
};
struct OpWithoutArg
{
// Add dummy type to default constructor but give it a default value
// You may still call it like a default constructor without arguments!
OpWithoutArg(DefaultConstructTag tag = {}) {}
};
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()
{
// Now this code should work
using SequenceType = OpsSequence<Op1WithArg, OpWithoutArg>;
SequenceType sequence{1, DefaultConstructTag{}};
}