I work on a code base where the C++ API is about to change (master branch and feature branch) and I want to protect my code against the change, such that my code builds against both versions. As minimum working example godbolt/compiler-explorer link:
common:
class SmallWidget {
private:
int m_i;
public:
int i() { return m_i; }
};
master:
class BigWidget {
private:
std::vector<SmallWidget*> m_v;
public:
auto& widgets() { return m_v; }
};
feature branch:
class BigWidget {
private:
std::vector<SmallWidget> m_v;
public:
auto& widgets() { return m_v; }
};
/**/
For the master version I have some call code:
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;
}
The API does not come with a preprocessor variable to select with
#if WIDGET_VERSION == OLD
return (*w.widgets().begin())->i(); // asterisk will need to go
#else
return (w.widgets().begin())->i(); // asterisk gone
#endif
I was trying to detect the return type of widgets
with sfinae:
// 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(); }
But the compilers are not happy about that. clang says:
<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
template
Is there a way to use sfinae to enable the right code here?
I also tried using std::enable_if
for the return code or function arguments, but my understanding is that the compiler always sees the signature int single_op(BigWidget&)
for both versions.
Aucun commentaire:
Enregistrer un commentaire