我在将要更改C ++ API的代码库(主分支和功能分支)上工作,我想保护我的代码不被更改,从而使我的代码针对两个版本构建。作为最低工作示例godbolt/compiler-explorer link:
常见:
class SmallWidget {
private:
int m_i;
public:
int i() { return m_i; }
};
主人:
class BigWidget {
private:
std::vector<SmallWidget*> m_v;
public:
auto& widgets() { return m_v; }
};
功能分支:
class BigWidget {
private:
std::vector<SmallWidget> m_v;
public:
auto& widgets() { return m_v; }
};
/**/
对于主版本,我有一些调用代码:
int single_op(BigWidget& w) {
return (*w.widgets().begin())->i(); // asterisk will need to go
}
std::vector<int> do_stuff(std::vector<BigWidget> inputs) {
std::vector<int> retval;
for (auto w : inputs) {
retval.push_back(single_op(w));
}
return retval;
}
API没有附带要选择的预处理器变量
#if WIDGET_VERSION == OLD
return (*w.widgets().begin())->i(); // asterisk will need to go
#else
return (w.widgets().begin())->i(); // asterisk gone
#endif
我正尝试使用sfinae检测widgets
的返回类型:
// version for the master branch API
template <typename = typename std::enable_if<std::is_same<
std::remove_const<std::remove_reference<decltype(**(
std::declval<BigWidget>().widgets().begin()))>::type>::type,
SmallWidget>::value>::type>
int single_op(BigWidget& w) {
return (*w.widgets().begin())->i();
}
// version for the feature branch API
template <typename = typename std::enable_if<std::is_same<
std::remove_const<std::remove_reference<decltype(*(
std::declval<BigWidget>().widgets().begin()))>::type>::type,
SmallWidget>::value>::type>
int single_op(BigWidget& w) { return w.widgets().begin()->i(); }
但是编译器对此并不满意。叮当声:
<source>:43:46: error: failed requirement 'std::is_same<std::remove_const<std::remove_reference<decltype(* (std::declval<BigWidget>().widgets().begin()))>::type>::type, SmallWidget>::value'; 'enable_if' cannot be used to disable this declaration
模板
是否可以使用sfinae在此处启用正确的代码?
我还尝试使用std::enable_if
作为返回码或函数参数,但我的理解是,对于这两个版本,编译器始终会看到签名int single_op(BigWidget&)
。
答案 0 :(得分:0)
我可以提出this版本:
// version for the feature branch API
template <typename bigtype>
int single_op(
typename std::enable_if<
std::is_same<
std::remove_const<std::remove_reference<decltype(
*(std::declval<BigWidget>().widgets().begin()))>::type>::type,
SmallWidget>::value,
bigtype>::type& w) {
return w.widgets().begin()->i();
}
我为BigWidget类型添加了一个额外的模板参数(尽管已知),并将其用于single_op
的函数参数。现在,编译器可以遍历这两个模板定义,提供一种针对过载集的可能解决方案,并禁用未使用的代码。
作为缺点,我现在必须在调用方拼写出模板参数
retval.push_back(single_op<decltype(w)>(w));
但是我怀疑那里有更好的解决方案。
答案 1 :(得分:0)
创建一个小辅助函数,将使用两种类型的任意一种并返回所需的类型。
SmallWidget &getWidget(SmallWidget *w) { return *w; }
SmallWidget &getWidget(SmallWidget &w) { return w; }
int single_op(BigWidget &w) {
return getWidget(*w.widgets().begin()).i();
}
您还可以为const
版本提供重载。