2017-07-10 10 views
4

Cのメンバー関数の1つの定義内でクラスCclass template argument deductionを使用することはできますか? ...またはmake_cヘルパークラスをC++ 03のように書く必要がありますか?クラス定義内からのテンプレート引数のタイプの差し引き

template <typename F> 
struct node; 

template <typename FFwd> 
node(FFwd&&) -> node<std::decay_t<FFwd>>; 

nodeクラス格納完全転送を介して初期化された関数オブジェクト:

この任意の機能オブジェクトのチェーンを構築し、最小化し、簡素化シナリオを検討してください。私は機能 オブジェクトの種類をdecayためにここに控除ガイドを必要としています。

template <typename F> 
struct node 
{ 
    F _f; 

    template <typename FFwd> 
    node(FFwd&& f) : _f{std::forward<FFwd>(f)} 
    { 
    } 

    template <typename FThen> 
    auto then(FThen&& f_then) 
    { 
     return node{[f_then = std::move(f_then)] 
        { 
         return f_then(); 
        }}; 
    } 
}; 

はその後、私はnodeのコンストラクタと新しいノード(その実装は例のサイズを最小化するために無意味である)を返す.then継続メンバ関数を定義します。私は.then ...

auto f = node{[]{ return 0; }}.then([]{ return 0; }); 

を起動しようとすると...私は予期しないコンパイルエラーを取得:

prog.cc: In instantiation of 'node<F>::node(FFwd&&) [with FFwd = node<F>::then(FThen&&) [with FThen = main()::<lambda()>; F = main()::<lambda()>]::<lambda()>; F = main()::<lambda()>]': 
prog.cc:27:22: required from 'auto node<F>::then(FThen&&) [with FThen = main()::<lambda()>; F = main()::<lambda()>]' 
prog.cc:35:56: required from here 
prog.cc:17:46: error: no matching function for call to 'main()::<lambda()>::__lambda1(<brace-enclosed initializer list>)' 
    node(FFwd&& f) : _f{std::forward<FFwd>(f)} 
              ^
prog.cc:35:20: note: candidate: 'constexpr main()::<lambda()>::<lambda>(const main()::<lambda()>&)' 
    auto f = node{[]{ return 0; }}.then([]{ return 0; }); 
        ^

live example on wandbox

node<F>::thenの体内に、node{...}が作成されるため、この問題が発生しましたタイプが*thisのインスタンス - 引数タイプの控除をトリガーしません。私は、したがって、書くことを強制しています:控除ガイドの全体の目的に反し

template <typename FThen> 
auto then(FThen&& f_then) 
{ 
    auto l = [f_then = std::move(f_then)]{ return f_then(); }; 
    return node<std::decay_t<decltype(l)>>{std::move(l)}; 
} 

live example on wandbox

を...。

コードの繰り返しやmake_node機能を導入せずに、ここでクラステンプレート引数の控除を使用できる方法はありますか?

答えて

6

nodeの名前ルックアップは、注入されたクラス名を見つけました。 (この場合、実行控除は、下位互換性のブレークされていると思います。)

あなたが控除をしたい場合は、名前空間のメンバーを見つけるように、名前を修飾します。

template <typename FThen> 
auto then(FThen&& f_then) 
{ 
    return ::node{[f_then = std::move(f_then)] 
    //  ^^ 
       { 
        return f_then(); 
       }}; 
} 

はまた、ガイドを書くためのクリーンな方法が

template <typename F> 
node(F) -> node<F>; 
+0

当たり前ですが、私は、私は、単純な何かが欠けた感がありました。乾杯。できるだけ早く受け入れます。 –

+0

控除ガイドのタイプが役に立たないのですか?または、「クリーナーガイド」は何ですか? –

+0

@MárioFeroldiガイドが転送参照で引数を取る場合は、手動で型を壊さなければなりません(OPのユースケースの場合)。それが価値によって引数を取るならば、言語はあなたのための腐敗を行い、あなたはそれを手作業で崩壊させる必要はありません。 –

0

は、私は可能な解決策を見つけたが、それはmake機能の外部実装を必要としません。

良いニュース:それはmake_nodeである必要はありません - それはクラステンプレート引数の減算をサポートする任意のタイプTで動作できます。

template <template <typename...> class T, typename... Ts> 
auto make(Ts&&... xs) 
    noexcept(noexcept(T{std::forward<Ts>(xs)...})) 
    -> decltype(T{std::forward<Ts>(xs)...}) 
{ 
    return T{std::forward<Ts>(xs)...}; 
} 

使用法:控除が行われないから

template <typename FThen> 
auto then(FThen&& f_then) 
{ 
    return make<node>([f_then = std::move(f_then)] 
        { 
         return f_then(); 
        }); 
} 
関連する問題