Ответ 1
Я бы порекомендовал:
template <class CType>
auto AliasGetNode(CType& cobject) -> decltype(cobject.getNode(0))
{
return cobject.getNode(0);
}
Это должно работать с С++ 11
У меня есть некоторый класс C
с const
и не const
getters для некоторого общего типа Node
:
template <typename NodeType>
class CParent{};
class Node {};
class C : public CParent<Node> {
Node& getNode(Index i);
const Node& getNode(Index i) const;
};
Теперь я хочу создать функцию псевдонима, которая вызывает getNode
для объекта класса C
:
template <class CType>
NodeType& AliasGetNode(CType* cobject);
Но как я могу сделать вывод NodeType
? то есть, если я называю AliasGetNode<const C>(c)
и AliasGetNode<C>(c)
, NodeType
должен быть соответственно const Node&
и Node&
.
Как я могу это сделать?
Я попробовал подходы result_of
и decltype
, но не был успешным.
Я бы порекомендовал:
template <class CType>
auto AliasGetNode(CType& cobject) -> decltype(cobject.getNode(0))
{
return cobject.getNode(0);
}
Это должно работать с С++ 11
Пусть компилятор выводит возвращаемый тип (с С++ 14):
template <class CType>
decltype(auto) AliasGetNode(CType& cobject)
{
return cobject.getNode(0);
}
Определите простой вспомогательный признак, который добавит/удалит const
из типа, основанного на том, есть ли другой тип const
:
template <class Src, class Dst>
using copy_const = typename std::conditional<
std::is_const<Src>::value,
const Dst,
typename std::remove_const<Dst>::type
>::type;
И используйте его:
template <class CType>
copy_const<CType, NodeType>& AliasGetNode(CType* cobject);
Так как С++ 14, компилятор может вывести тип возвращаемой функции:
template<typename CType>
decltype(auto) AliasGetNode(CType& cobject) {
return cobject.getNode();
}
Когда вы вызываете AliasGetNode
объекта типа Node
, CType
выводится на Node
. Но если вы вызываете AliasGetNode
на объект типа const Node
, CType
выводится на const Node
.
Важно сделать тип возврата AliasGetNode
как decltype(auto)
, иначе вы потеряете ссылку и константу для возвращаемого типа.
Вы должны написать две функции псевдонимов: одну для неконстантного экземпляра, а другую для экземпляра const:
template <class CType>
const NodeType& AliasGetNode(const CType* cobject) const; // for const instance.
// The function must be const since the only difference between return type will cause redefinition error.
template <class CType>
NodeType& AliasGetNode(CType* cobject); // for non-const instance
Инстанции, объявленные const, будут вызывать функции const, если есть функции перегрузки. Конечно, неконстантные экземпляры вызовут неконстантную версию функции перегрузки. Например:
class Aclass {
public:
string test() { return "calling non-const function"; }
string test() const { return "calling const function"; }
};
int main() {
Aclass a;
const Aclass b;
cout << a.test() << endl;
cout << b.test() << endl;
return 0;
}
Результат будет:
calling non-const function
calling const function