web-dev-qa-db-ja.com

関数テンプレートの戻り値の型の推定

いくつかのジェネリック型C用のconstと非constゲッターを持ついくつかのクラス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アプローチを試しましたが、成功しませんでした。

11
manatttta

私はお勧めします:

template <class CType>
auto AliasGetNode(CType& cobject) -> decltype(cobject.getNode(0))
{
    return cobject.getNode(0);
}

これはc ++ 11以降はかなり機能するはずです

12
W.F.

コンパイラに戻り値の型を推測させます(C++ 14以降):

template <class CType>
decltype(auto) AliasGetNode(CType& cobject)
{
    return cobject.getNode(0);
}
20

別のタイプが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);
5
Angew

C++ 14以降、関数の戻り値の型はコンパイラーによって推測される可能性があります。

_template<typename CType>
decltype(auto) AliasGetNode(CType& cobject) {
    return cobject.getNode();
}
_

タイプAliasGetNodeのオブジェクトでNodeを呼び出すと、CTypeNodeに推定されます。ただし、タイプ_const Node_のオブジェクトでAliasGetNodeを呼び出すと、CTypeは_const Node_に推定されます。

AliasGetNodeの戻り値の型をdecltype(auto)として作成することが重要です。そうしないと、返される型の参照と定数を見逃してしまいます。

4
Edgar Rokjān

2つのエイリアス関数を作成する必要があります。1つは非constインスタンス用で、もう1つは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関数を呼び出します。もちろん、非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
3
Ruby Yip