【问题标题】:Is there a way to cast Template's Type to shared_ptr<T>?有没有办法将模板的类型转换为 shared_ptr<T>?
【发布时间】:2016-01-13 14:03:04
【问题描述】:

最近,我正在为一所学校的作业工作,该作业即将通过使用类和对象来构造一个非常简单的多项式表达式。 我们不必构造 parse function ,所以要构造一个正常的表达式,需要编写很多代码,并且当代码很多时很难辨别。所以我认为这也许是尝试 C++ 模板的一个很好的环境(我真的是 C++ 的新手,所以我对模板不是很有经验,不确定在这种情况下我是否可以使用它。) 例如,我需要实现 OperatorPlus,其声明对应者为std::shared&lt;Expression&gt; OperateurPlus(std::shared&lt;Expression&gt;, std::shared&lt;Expression&gt;)。我想创建template&lt;typename T, typename M&gt; std::shared&lt;Expression&gt; plus(T lhs, M rhs) 包装器来响应不同的传入参数。我按照另一种语言的 where 子句通过使用enable_if 添加类型限制。所以代码是这样的:

template<typename T, typename M,
        typename = std::enable_if<(
                                   std::is_same<unsigned int, T>::value ||
                                   std::is_same<char, T>::value ||
                                   std::is_same<std::shared_ptr<Expression>, T>::value) &&
        ( std::is_same<unsigned int, M>::value ||
         std::is_same<std::shared_ptr<Expression>, M>::value ||
         std::is_same<char, M>::value)>
        >
        std::shared_ptr<Expression> plus(T lhs, M rhs){
            std::shared_ptr<Expression> t_lhs, t_rhs;
            if (std::is_same<T, uint>::value) t_lhs = Nombre::create(uint(lhs));
            if (std::is_same<T, char>::value) t_lhs = std::shared_ptr<Expression>(new Variable(char(lhs)));
            if (std::is_same<T, std::shared_ptr<Expression>>::value) t_lhs = (std::shared_ptr<Expression>)(lhs);

            if (std::is_same<M, uint>::value) t_rhs = Nombre::create(uint(rhs));
            if (std::is_same<M, char>::value) t_rhs = std::shared_ptr<Expression>(new Variable(char(rhs)));
            if (std::is_same<M, std::shared_ptr<Expression>>::value) t_rhs = (std::shared_ptr<Expression>)(rhs);
            return std::shared_ptr<Expression>(new OperateurPlus(t_lhs, t_rhs));
        }

我的问题是(std::shared_ptr&lt;Expression&gt;)(lhs) 这部分。我使用了 c 风格的铸造,因为我不知道如何实现这种铸造操作。 IDE 告诉我的 std::shared_ptr 不是指针或引用,如果我尝试了 static_cast> 并且它认为 lhs 是 unsigned int 类型。 所以如果我只是按照编译的提示,我的问题是

  1. 如何将模板的类型转换为 std::shared_ptr?或

  2. 是否可以将 std::shared_ptr 作为模板参数传递?

【问题讨论】:

  • 您可以创建辅助函数,例如 auto make_expression(const std::shared_ptr&lt;Expression&gt;&amp; expr) { return expr; }(如果它已经是一个表达式,则什么都不做),以及将整数提升为 Expressions 的其他重载。
  • 对于共享指针std::shared_ptr&lt;Expression&gt; ptr,可以使用std::static_pointer_cast&lt;Expression&gt;(ptr)进行静态转换

标签: templates c++11 casting smart-pointers


【解决方案1】:

对于给定的模板实例化,模板函数的主体必须是完全可编译的。即使永远不会访问这些 if 语句之一,条件仍然需要在语法上对适当的类型有效。

为此使用单一功能是错误的方法。一种可能的解决方案是创建一个重载函数以从您所需的任何来源获取std::shared_ptr,然后使用该函数来实现所需的通用性。

using ExpPtr = std::shared_ptr<Expression>; //for brevity

ExpPtr convertToExp (ExpPtr e) {
    return e;
}

ExpPtr convertToExp (unsigned int i) {
    return Nombre::create(i);
}

ExpPtr convertToExp (char c) {
    return std::make_shared<Variable>(c);
}

template <typename T, typename U>
ExpPtr plus (T lhs, U rhs) {
    auto lhsExp = convertToExp(lhs);
    auto rhsExp = convertToExp(rhs);
    return std::make_shared<OperateurPlus>(lhsExp, rhsExp);
}

我不认为所有的 SFINAE 都是必要的。如果没有对convertToExpTU 的有效调用,这将硬失败。

我没有尝试编译,因为您没有提供 MVCE,所以可能会有一些错误。


如果您真的希望 SFINAE 防止在 convertToExp 调用中进行隐式转换,您可以使用如下更简洁的方式来实现:

template<typename... Conds>
struct or_ : std::false_type {};

template<typename Cond, typename... Conds>
struct or_<Cond, Conds...>
        : std::conditional_t<Cond::value, std::true_type,
        or_<Conds...>> {};

template <typename T, typename... Ts>
using is_one_of = or_<std::is_same<T,Ts>...>;

template <typename T>
using is_valid_exp_source = 
    is_one_of<T, char, unsigned int, std::shared_ptr<Expression>>;

template <typename T, typename U>
std::enable_if_t<is_valid_exp_source<T>::value && is_valid_exp_source<U>::value, 
                 ExpPtr> 
plus (T lhs, U rhs) {
    auto lhsExp = convertToExp(lhs);
    auto rhsExp = convertToExp(rhs);
    return std::make_shared<OperateurPlus>(lhsExp, rhsExp);
}

【讨论】:

    猜你喜欢
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 2012-07-22
    • 1970-01-01
    相关资源
    最近更新 更多