最近,我正在为一所学校的作业工作,即将使用类和对象构建一个非常简单的多项式表达式。
我们不必构造解析函数,因此要构造一个普通表达式,需要编写很多代码,并且在有很多代码时很难辨别。所以我想也许这是一个很好的上下文来尝试C ++模板(我真的是C ++的新手,所以我对模板不是很有经验,不确定在这种情况下我是否可以使用它。)
例如,我需要实现其声明对应为std::shared<Expression> OperateurPlus(std::shared<Expression>, std::shared<Expression>)
的OperatorPlus。我想创建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&gt;它认为lhs是unsigned int类型。
所以,如果我只是按照编译的提示,我的问题是
如何将模板的Type转换为std :: shared_ptr?或
如果可以将std :: shared_ptr作为模板参数传递?
答案 0 :(得分: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都是必要的。如果convertToExp
或T
没有对U
的有效来电,则会很难失败。
我没有尝试编译这个,因为你没有提供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);
}