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

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

我有一个模板化的classeglue,它根据传入的参数之一确定自己的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,这将是 eglue 或 [=17] =]对象。

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

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>()(如有必要,我会 post 这些,但我已经看到它在其他情况下也有效)。

我知道这可能与其他问题重复或相似,但我真的无法让它发挥作用...任何建议将不胜感激。

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

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

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

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

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) {}
};