如何在C++中使用编译时三元运算符来获取对象成员

How to use compile-time ternary operator in C++ to get object member

本文关键字:三元 运算符 成员 取对象 获取 C++ 编译      更新时间:2023-10-16

我有一个模板化类eglue,它根据传入的参数之一确定自己的n_rows和n_cols,保证具有n_rows和n_cols成员。代码如下:

template<typename> struct isEglueOrMat : std::false_type {};
template<typename T1, operations _op, typename T2> struct isEglueOrMat<eglue<T1, _op, T2>> : std::true_type {};
template<> struct isEglueOrMat<Matrix> : std::true_type {};
template<typename T1, operations _op, typename T2>
class eglue {
public:
const T1& First;
const T2& Second;
const unsigned n_rows;
const unsigned n_cols;
eglue(const T1& f, const T2& s) : First(f), Second(s), n_rows(isEglueOrMat<T1>()? f.n_rows:s.n_rows), n_cols(isEglueOrMat<T1>()? f.n_cols:s.n_cols) {}

这不起作用,失败并出现错误request for member 'n_rows' in 'f', which is of non-class type 'const float',当我只想从另一个项目获取n_rows时,这将是一个eglueMatrix的对象。

我尝试过的另一种方法是模板化构造函数:

template<typename Dummy = void, typename Dummy2 = std::enable_if_t<isEglueOrMat<T1>(), Dummy>> eglue(const T1& f, const T2& s) : First(f), Second(s), n_rows(f.n_rows), n_cols(f.n_cols) {}
template<typename Dummy = void, typename Dummy2 = std::enable_if_t<isEglueOrMat<T2>(), Dummy>> eglue(const T1& f, const T2& s) : First(f), Second(s), n_rows(s.n_rows), n_cols(s.n_cols) {}

此操作失败并显示错误

type/value mismatch at argument 1 in template parameter list for 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type'
template<typename Dummy = void, typename Dummy2 = std::enable_if_t<isEglueOrMat<T1>(), Dummy>> eglue(const T1& f, const T2& s) : First(f), Second(s), n_rows(f.n_rows), n_cols(f.n_cols) {}
                      ^
error:   expected a constant of type 'bool', got 'isEglueOrMat<T1>()'

即使我已经在代码的其他点成功使用了isEglueOrMat<type>()(如有必要,我会发布这些内容,但我已经看到它在其他情况下有效)。

我知道这可能是重复的或类似于其他问题,但我真的无法让它工作......任何建议将不胜感激。

编辑:我是个白痴,第二种方法无论如何都行不通,因为你不能用相同的签名重载构造函数...... 有没有办法使第一种方法(或任何其他方法!)起作用?

您可以将标记调度与委派构造函数一起使用:

template<typename T1, operations _op, typename T2>
class eglue {
public:
const T1& First;
const T2& Second;
const unsigned n_rows;
const unsigned n_cols;
eglue(const T1& f, const T2& s) : eglue(f,s,isEglueOrMat<T1>()) {}
private:
eglue(const T1& f, const T2& s, std::true_type)  : First(f), Second(s), n_rows(f.n_rows), n_cols(f.n_cols) {}
eglue(const T1& f, const T2& s, std::false_type) : First(f), Second(s), n_rows(s.n_rows), n_cols(s.n_cols) {}
};

或者第二种方法,确保间接依赖于T1

template<typename T1, operations _op, typename T2>
class eglue {
public:
const T1& First;
const T2& Second;
const unsigned n_rows;
const unsigned n_cols;
template <typename _T1 = T1, std::enable_if_t<isEglueOrMat<_T1>{}, bool> = true>
eglue(const T1& f, const T2& s)  : First(f), Second(s), n_rows(f.n_rows), n_cols(f.n_cols) {}
template <typename _T1 = T1, std::enable_if_t<!isEglueOrMat<_T1>{}, bool> = false>
eglue(const T1& f, const T2& s)  : First(f), Second(s), n_rows(s.n_rows), n_cols(s.n_cols) {}
};

对于第二种工作方法,您应该使用isEglueOrMat<T>::value作为布尔常量。当你使用isEglueOrMat<T>()时,它被视为类型为integral_constant的对象,一个结构。当你在其他布尔表达式中使用它时,它被静默地强制为 bool(std::integral_constant确实提供了这样的运算符)。另一种选择是将其显式转换为布尔值,static_cast<bool>(isEglueOrMat<T>())也有效,C 样式的强制转换也是如此。

第一种方法也可以变得可行,但它需要更多的间接性(普通的标准运算符不会像你看到的那样工作)和一些乍一看很棘手的 SFINAE 游戏。