如何在 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) {}
};
我有一个模板化的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) {}
};