4

boost::variant があり、バリアントが特別なタイプの場合にのみファンクターを実行したいので、次の関数を作成しました。

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
    if(auto* ptr = boost::get<T>(&opt_variant)){
        functor(*ptr);
    }   
}

これはうまく機能しますが、次のように記述できるように、型 T を推定したいと思います。

if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

しかし、型は推測されません:

type_inference.cpp:19:5: error: no matching function for call to 'if_init'
    if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 
    ^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
    void if_init(Variant& opt_variant, std::function<void(T)> functor){

私が書く場合:

if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

それはうまくいきます。

タイプ T を推定する方法はありますか? T を 1 回だけ入力したいと思います。ここではショートタイプですが、実際にはロングタイプもあります。

私はCLang 3.2を使用しています。

完全なテスト ケースは次のとおりです (最初の呼び出しは 2 番目の呼び出しではなくコンパイルされます)。

#include <iostream>
#include <functional>
#include <boost/variant.hpp>

typedef boost::variant<int, double> Test;

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
    if(auto* ptr = boost::get<T>(&opt_variant)){
        functor(*ptr);
    }   
}

int main(){
    Test b = 1.44; 

    if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
    if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });      

    return 0;
}
4

1 に答える 1

6

std::function<Sig>署名として準拠する任意の 1 つのファンクターのコンテナーと考え​​ることをお勧めします。Sigこれはいつでも置き換えることができます。この機能は、たとえば、そのようなコンテナーがさまざまなstd::vector<std::function<Sig>>タイプのファンクターを保持できるため、非常に便利です。

あなたの場合、 の機能を本当に必要としないファンクターを 1 つだけ持つことに関心があるためですstd::function<Sig>。そのため、関数テンプレートを次のように宣言することをお勧めします。

template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);

Functorこれが署名に準拠する必要があることを伝えていないのではないかと心配している場合は、それを強制するものではないvoid(T)ことに注意してください。これは変更される予定です (実装にも変更がある可能性があります) が、別の種類のエラーに変更されました。あなたのケースにはまだそれほど役に立ちません。std::function<Sig>

私は個人的に、(テンプレート パラメーター リスト内の) テンプレート エイリアスを使用して、ファンクターが従うべきものを文書化し、強制します。これは最終的に次のようになります。

// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);

// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);

あなたの正確な質問に関しては、C++ の規則では、テンプレート パラメーターをあなたのケースで推測することはできません。それが 1 つである場合、それは本当に簡単に修正できる「問題」ではありません。これに関する詳細情報を見つけることができます。

于 2013-02-09T03:20:02.460 に答える