我如何提取和使用 C++ 类的变量模板参数中定义的类型,而不是定义以下类的多个重复项,这些重复项仅按参数的数量和类型进行延迟:
template <typename T1, typename T2>
class SUTTestFixture1
{
public:
void SetUp(T1 expected, vector<T2> data)
{
_expected = expected;
_data = data;
}
protected:
SUT _sutObj;
vector<T2> _data;
T1 _expected;
};
template <typename T1, typename T2, typename T3>
class SUTTestFixture2
{
public:
void SetUp(T1 expected, T2 param, vector<T3> data)
{
_expected = expected;
_param = param;
_data = data;
}
protected:
SUT _sutObj;
vector<T2> _data;
T1 _expected;
T2 _param;
};
我希望能够仅使用带有变量模板参数的单个类:
template <typename... T>
class SUTTestFixture
{
public:
void SetUp(T... args)
{
_expected = args...[0];
_data = args...[1]; // expected ‘;’ before ‘...’ token
}
protected:
SUT _sutObj;
vector<T...> _data; // XXX
T... _expected; // error: expected unqualified-id before ‘...’ token
};
SUTTestFixture1
用例:
class TestFixture1 : public SUTTestFixture1<long, long>, public testing::TestWithParam<tuple<long, vector<long>>>
{
public:
void SetUp() override
{
RangeTestFixture1::SetUp(get<0>(GetParam()), get<1>(GetParam()));
}
long Function1Test()
{
return _sutObj.Function1(_data);
}
};
SUTTestFixture2
用例:
class TestFixture2 : public SUTTestFixture2<size_t, size_t, size_t>, public testing::TestWithParam<tuple<size_t, size_t, vector<size_t>>>
{
public:
void SetUp() override
{
RangeTestFixture2::SetUp(get<0>(GetParam()), get<1>(GetParam()), get<2>(GetParam()));
}
size_t Function2Test()
{
return _sutObj.Function2(_param, _data);
}
};
您不需要所有值的第二个副本,您可以直接继承
Testing::TestWithParam
template <typename R, typename... Args>
class SUTTestFixture : public testing::TestWithParam<std::tuple<R, Args...>>
{
public:
R Expected() {
return std::get<0>(this->GetParam());
}
template <typename Method>
R Actual(Method method) {
// Peel Expected off the front, and then call _sutObj.Method(args...)
return std::apply([&](auto&&, auto&&... args){
return std::invoke(method, _sutObj, args...);
}, this->GetParam());
}
protected:
SUT _sutObj;
};
class TestFixture1 : public SUTTestFixture<long, std::vector<long>>
{
};
class TestFixture2 : public SUTTestFixture<size_t, size_t, std::vector<size_t>>
{
};
INSTANTIATE_TEST_SUITE_P(TestFunction1, TestFixture1, testing::Combine(testing::Values(1L), testing::Values(std::vector{1L})));
TEST_P(TestFixture1, Foo) {
EXPECT_EQ(Expected(), Actual(&SUT::Function1));
}
INSTANTIATE_TEST_SUITE_P(TestFunction2, TestFixture2, testing::Combine(testing::Values(1uz), testing::Values(1uz), testing::Values(std::vector{1uz})));
TEST_P(TestFixture2, Foo) {
EXPECT_EQ(Expected(), Actual(&SUT::Function2));
}
作为替代方案,您可以为每个测试夹具的参数定义一个结构体,而不必担心
std::tuple
s
struct TestFixture1Params
{
long expected;
std::vector<long> data;
};
class TestFixture1 : public testing::TestWithParam<TestFixture1Params>
{
public:
long Function1Test()
{
return _sutObj.Function(GetParam().data);
}
protected:
SUT _sutObj;
};
struct TestFixture2Params
{
size_t expected;
size_t param;
std::vector<size_t> data;
};
class TestFixture2 : public testing::TestWithParam<TestFixture2Params>
{
public:
size_t Function2Test()
{
return _sutObj.Function(GetParam().param, GetParam().data);
}
protected:
SUT _sutObj;
};
您必须从模板参数列表中独立提取第一个 n-1 和最后一个参数,然后将它们写入自变量。 如果您首先接收向量参数,然后接收其余参数,那么这个过程会容易得多。但就目前情况而言,您必须使用辅助类型进行一些模板参数列表操作。
template <typename... Ts>
struct LastArg {};
template <typename T0, typename T1, typename... Ts>
struct LastArg<T0, T1, Ts...> : LastArg<T1,Ts...> {
};
template <typename T>
struct LastArg<T> {
using type = T;
};
template <typename T0, typename AL>
struct PrependToList{};
template <typename T0, typename... Ts>
struct PrependToList<T0, std::tuple<Ts...>> {
using type = std::tuple<T0, Ts...>;
};
template <typename... Ts>
struct DropLast {};
template <typename T0, typename T1, typename... Ts>
struct DropLast<T0,T1,Ts...> {
using type = typename PrependToList<T0, typename::DropLast<T1,Ts...>::type>::type;
};
template <typename T>
struct DropLast<T> {
using type = std::tuple<>;
};
template <typename... T>
class SUTTestFixture {
public:
using Data = std::vector<typename LastArg<T...>::type>;
using Expect = typename DropLast<T...>::type;
void SetUp(Expect expect, Data data)
{
_expected = expect;
_data = data;
}
template <typename... U>
requires (std::is_same_v<typename DropLast<U...>::type,Expect> && std::is_same_v<typename LastArg<U...>::type, Data>)
void SetUp(U... us) {
SetUp(slice(std::tuple{us...}, std::make_index_sequence<sizeof...(us)-1>{}), std::get<sizeof...(U)-1>(std::tuple{us...}));
}
protected:
//SUT _sutObj;
Data _data;
Expect _expected;
template <typename Tup, std::size_t... I>
auto slice(Tup tup, std::index_sequence<I...>) {
return std::tuple{std::get<I>(tup)...};
}
};
这是一个演示。