【问题标题】:How to use compile-time ternary operator in C++ to get object member如何在 C++ 中使用编译时三元运算符来获取对象成员
【发布时间】:2018-01-05 13:05:50
【问题描述】:

我有一个模板类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) {}

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

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

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&lt;type&gt;()(如果有必要我会发布这些,但我已经看到它在其他情况下也有效)。

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

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

【问题讨论】:

  • isEglueOrMat() constexpr?否则不能作为模板参数使用。
  • 我在 template&lt;typename T1, typename T2&gt; std::enable_if_t&lt;(isEglueOrMat&lt;T1&gt;() || isNumeric(T1)) &amp;&amp; (isEglueOrMat&lt;T2&gt;() || isNumeric(T2)), eglue&lt;T1, ADD, T2&gt;&gt; operator +(const T1&amp; first, const T2&amp; second) { return eglue&lt;T1, ADD, T2&gt;(first, second); } 中使用过它,它编译得非常好......即使它不是 constexpr 我也不明白为什么它会在这里工作而不在那里工作。
  • isNumeric 是宏吗?否则我看不出你怎么能使用这个表达式。
  • 是的,我已经用 std::is_integralstd::is_floating_point... 再次定义了它,这不是问题。 ://
  • 你想具体实例化什么? eglue&lt;float, ..., float&gt;?目前尚不清楚T1/T2 可能的“类型”是什么...

标签: c++ templates constructor c++14 sfinae


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 我不认为你可以声明结构constexpr?还是我错过了什么?
    • 哦,这是一个结构,对不起,我错过了。编辑帖子。
    • 你的答案没有意义“当你在其他布尔表达式中使用它时,它被默默地强制转换为布尔值。”,这正是你想要的......
    猜你喜欢
    • 2020-01-27
    • 2012-12-18
    • 2021-09-19
    • 1970-01-01
    • 2010-12-13
    • 2017-05-12
    • 2020-02-21
    • 2020-11-23
    • 2015-09-21
    相关资源
    最近更新 更多