我有一个包含元组的模板类。
template <class... SomeTypes>
class Foo
{ ... };
如何对 SomeTypes 参数包中包含的类型应用约束?例如,如果我想确保所有类型都符合这个std::movable
概念?
如果SomeTypes
也是模板怎么办?
template < template<typename> class... SomeTypes>
class Bar
{ ... };
以下是我正在寻找的更具体的情况。该代码不应该(并且不会)编译,因为FooB
它不可复制。
不幸的是,编译器在遇到这种情况时并没有给出最清晰的错误信息(在我处理的实际代码中,类型更加复杂,最终导致了大量错误信息)。我希望可以添加一些子句,requires
让它FooContainer
给出更清晰的错误信息。
#include <tuple>
#include <concepts>
template <typename ContainerType>
class Foo
{
};
template <typename ContainerType>
class FooA : public Foo<ContainerType>
{
public:
int some_data {0};
void DoSomething()
{
some_data++;
}
};
template <typename ContainerType>
class FooB : public Foo<ContainerType>
{
public:
// non-copyable object
FooB() = default;
FooB( const FooB& ) = delete;
FooB& operator=( const FooB& ) = delete;
~FooB() = default;
int some_data {0};
void DoSomething()
{
some_data++;
}
};
template < template<typename> class... SomeTypes>
// requires (std::copyable<SomeTypes...>) ???
class FooContainer
{
public:
std::tuple<SomeTypes<FooContainer>...> my_tuple;
template <std::size_t I = 0, std::enable_if_t<I == sizeof...(SomeTypes)>* = nullptr>
void DoAllThings()
{
}
template <std::size_t I = 0, std::enable_if_t<I < sizeof...(SomeTypes)>* = nullptr>
void DoAllThings()
{
std::get<I>(my_tuple).DoSomething();
DoAllThings<I + 1>();
}
};
using MyContainer = FooContainer<FooA, FooB>;
int main()
{
MyContainer my_bar;
my_bar.DoAllThings();
MyContainer my_bar2 = my_bar;
}
--编辑 2--
因此,在尝试了这里的一些建议之后,我想到最接近我想要的就是使用外部静态函数来进行检查。
template <typename FooType>
requires (std::copyable<FooType>)
constexpr bool FooTypeCheck()
{
return true;
}
static_assert(FooTypeCheck<FooA<int>>());
这给了我想要的检查(派生的 Foo 类是否可复制),因此如果检查失败,编译器的输出更容易阅读。对于类型检查来说,ContainerType 无关紧要,所以我只传递了一个 int 值。不幸的是,这也意味着我需要为每个派生的 Foo 类添加 static_assert,而我传递给 ContainerType 的 int 值有点奇怪。
--最终编辑(答案)-- 我感谢@Ted Lyngmo的回答,因为它接近我的需求。由于ContainerType参数只是CRTP的一部分,因此对于约束而言,它实际上无关紧要,而且我可以直接使用int,这样解决方案就更简单一些了。
template <template <typename> class FooType>
concept FooTypeCheck = std::copyable<FooType<int>>;
template < template<typename> class... SomeTypes>
requires (... && FooTypeCheck<SomeTypes>)
class FooContainer
{ ... };
最直接的方法是使用以下
std::movable
概念:类模板可以特化,但你无法检查类模板是否对所有类型都可移动。你需要类模板的实际实例才能检查其可移动性。
例如,如果您想检查所提供的类模板在使用
int
和实例化时是否可以移动std::string
,您可以像这样检查:您可以在模板上放置一个需要子句:
如果您希望将需求排除在类定义之外,您可以执行以下操作:
下面回答了当
SomeTypes
是模板类时更尴尬的情况。你可以检查类的某些属性,但对于像 这样的模板类则不行,
FooA
因为它不是一个类型(它代表一个类型族)。当你通过为其模板形参提供类型实参来实例化它时,它就变成了一个真正的类型。例如,你可以检查 的某些类型属性,但通常FooA<int>
不能检查的某些类型属性。FooA
因此,您可以提供给
DoAllThings
这个模板参数,然后进行一些概念检查(例如,类型是否是默认可构造的):并像使用它一样
std::is_default_constructible
正如预期的那样,这将在我们的示例中产生引用类型特征的错误演示