有没有办法将模板的类型转换为shared_ptr<T>?



最近,我正在为学校的作业工作,这是关于使用类和对象构造一个非常简单的多项式表达式。我们不需要构造解析函数,所以构造一个正常的表达式需要写很多代码,当有很多代码时很难辨别。所以我认为,也许这是一个很好的背景下,尝试c++模板(我真的是一个新鲜的人c++,所以我不是那么有经验的模板,不确定如果在这种情况下,我可以使用它。)作为一个例子,我需要实现OperatorPlus的声明对应是std::shared<Expression> OperateurPlus(std::shared<Expression>, std::shared<Expression>)。我想创建template<typename T, typename M> std::shared<Expression> 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<Expression>)(lhs)这一部分。我使用c风格的强制转换,因为我不知道如何实现这种强制转换操作。IDE告诉我的std::shared_ptr不是一个指针或引用,如果我尝试static_cast>,它认为lhs是无符号int类型。如果我按照编译器的提示,我的问题是

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

  2. 如果有可能传递std::shared_ptr作为模板参数?

对于给定的模板实例化,模板函数体必须完全可编译。即使这些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是必要的。如果TU没有对convertToExp的有效调用,这将导致硬失败。

我没有尝试编译这个,因为你没有提供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);
}

相关内容

  • 没有找到相关文章

最新更新