带有if constexpr的C++非文本类型错误

C++ non-literal type error with if constexpr

本文关键字:文本 类型 错误 C++ if constexpr 带有      更新时间:2024-09-28

设置

我定义了两个模板类ContainerAContainerB,如所示

template <class... T>
class ContainerA{
public:
constexpr explicit ContainerA(T... data) : data_(data...) {}
constexpr explicit ContainerA(std::tuple<T...> data) : data_(data) {}
constexpr std::tuple<T...> getDataA() const { return data_; }
constexpr std::size_t getSize() const { return sizeof...(T); }

protected:
const std::tuple<T...> data_;
};

template <class T>
class ContainerB{
public:
constexpr explicit ContainerB(T data) : data_(data) {}
constexpr T getDataB() const { return data_; }
protected:
const T data_;
};

以及从上面派生的另一类:

template <class O, class... I>
class BiggerContainer : public ContainerA<I...>, public ContainerB<O>  {
public:
constexpr explicit BiggerContainer (O dataB, I... dataA) : ContainerA<I...>(data...), ContainerB<O>(dataB) {}
constexpr explicit BiggerContainer (O dataB, std::tuple<I...> dataA) : ContainerA<I...>(data), ContainerB<O>(dataB) {}
};

到目前为止什么还不错

首先,我想初始化一个std::tuple,即持有上面每个类的一个对象:

constexpr auto tup = std::make_tuple(ContainerA(1,2,3), ContainerB(0), BiggerContainer(0,1,2,3));

接下来,我希望能够在编译时评估if语句。据我所知,这可以用if constexpr来完成。该if语句应检查ContainerAContainerBBiggerContainer是否存储在tup中的某个位置。

template <class T>
struct IsBiggerContainerType: std::false_type {};
template <class... T>
struct IsBiggerContainerType<BiggerContainer<T...>> : std::true_type {};
template <class T>
constexpr bool isBiggerContainerType(T /*var*/) {
return IsBiggerContainerType<T>();
}
int main() {
constexpr auto element = std::get<2>(tup);
if constexpr (isBiggerContainerType(element)) {
std::cerr << "Hello World" << std::endl;
}
}

到目前为止,所有这些工作都很好

问题

现在我有一个额外的类Test,它将获得一个类似元组的tup,然后能够像上面一样在朋友函数中评估if constexpr

template <AbovesClassesConcept... PS>
class Test{
public:
explicit Test(std::tuple<PS...> data) : data_(data) {}
<template idx = 0>
friend constexpr void evaluate();
private:
const std::tuple<PS...> data_;
}
<template idx = 0>
constexpr void evaluate() {
// ... some tuple iteration stuff that works just fine

constexpr auto element = get<idx>(data_); 
if constexpr (isBiggerContainer(element)) {
// ... do something with element
}
// ... some other tuple iteration stuff that works just fine
}

但是在创建类似于此的Test实例时

constexpr auto tup = std::make_tuple(ContainerA(1,2,3), ContainerB(0), BiggerContainer(0,1,2,3));
constexpr Test test(tup);

我得到一个错误:

Constexpr变量不能具有非文字类型"const Test<容器A<int,int,int>,ContainerB,BiggerContainer<int,int,int>

问题是非常量友元函数,还是其他地方有问题?到目前为止我还想不通。感谢您的帮助!!提前感谢!

我觉得你想得太多了。另请参阅https://stackoverflow.com/a/31763111/9072753。

#include <type_traits>
#include <tuple>
#include <iostream>
template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};
template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};
//
template <class... T>
struct ContainerA {
constexpr explicit ContainerA(T... data) {}
};
template <class T>
struct ContainerB {
constexpr explicit ContainerB(T d) {}
};
template <class O, class... I>
struct BiggerContainer : public ContainerA<I...>, public ContainerB<O>  {
constexpr explicit BiggerContainer (O dataB, I... dataA) :
ContainerA<I...>(dataA...),
ContainerB<O>(dataB) {
}
};
constexpr std::tuple<ContainerA<int, int, int>, ContainerB<int>,
BiggerContainer<int, int, int, int>
> tup = std::make_tuple(
ContainerA(1,2,3),
ContainerB(0),
BiggerContainer(0,1,2,3)
);
template<int IDX, typename TUPLE>
using isBiggerContainer = is_specialization<
std::remove_const_t<std::tuple_element_t<IDX, TUPLE>>,
BiggerContainer>;
int main() {
static_assert(is_specialization<std::remove_const_t<std::tuple_element_t<0, decltype(tup)>>, ContainerA>{});
static_assert(!isBiggerContainer<0, decltype(tup)>{});
static_assert(!isBiggerContainer<1, decltype(tup)>{});
static_assert(isBiggerContainer<2, decltype(tup)>{});
}

,它将获得一个类似元组的元组,然后能够评估

element是运行时元素,decltype(element)是类型。

if constexpr (is_specialization<decltype(element), BiggerContainer>{}) {