4

という名前のクラスがあり、メンバー関数has_fを持つテンプレート パラメーターのみを受け入れるようにします。fどうすればいいですか?これは私が試したものです:

template <typename T, typename = void>
struct has_f : std::false_type {};

template <typename T>
struct has_f<
    T,
     typename = typename std::enable_if<
        typename T::f
    >::type
> : std::true_type {};

しかし、いくつかの不可解なエラーが発生します。使用したいクラスは次のとおりです。

struct A
{
    void f();
};

これを正しく行うにはどうすればよいですか?ありがとう。

4

3 に答える 3

2

あなたの質問のタイトルから、 true_type または false_type から派生した型は本当に必要ないと思います-メソッド f が存在しない場合にコンパイルを防ぐためだけです。その場合、およびそのメソッドに特定の署名 (少なくとも引数に関して) も必要な場合は、C++11 で次のようにすることができます。

template <typename T>
struct compile_if_has_f
{
    static const size_t dummy = sizeof(
        std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};

これは、f() が引数を受け入れてはならない場合です。sizeof(void) が不正であるため、 std::add_pointer は f が void を返す場合にのみ必要です。

于 2013-06-07T21:24:20.687 に答える
1

昨日、「クラスに指定された署名のメンバー関数があるかどうかを確認するの
重複の可能性」 について rapptz に +1 を付けましたが、気が変わっていません。

この質問は、「A)クラスに特定の署名のメンバー関数があるかどうかを確認する方法、およびB)クラステンプレートの引数がA)に従ってクラスであることを主張する方法」に展開されることは議論の余地があると思います。static_assertB) に対して、この場合、質問者は明らかにenable_if代替案に興味がないので、私は と答えます。

これは、「func(args) が適切な形式であり、戻り値の型が必要かどうかをテストするための特性」に対する私の回答を適応させるソリューション ですhas_f<T>::value。.void T::f()Tff

#include <type_traits>

template<typename T>
struct has_f
{   
    template<typename A>
    static constexpr bool test(
        decltype(std::declval<A>().f()) *prt) {
        return std::is_same<void *,decltype(prt)>::value;
    }

    template <typename A>
    static constexpr bool test(...) {
        return false; 
    }

    static const bool value = test<T>(static_cast<void *>(nullptr)); 
};

// Testing...

struct i_have_f
{
    void f();   
};
struct i_dont_have_f
{
    void f(int);    
};
struct i_also_dont_have_f
{
    int f();    
};
struct i_dont_quite_have_f
{
    int f() const;  
};
struct i_certainly_dont_have_f
{};

struct i_have_overloaded_f
{
    void f();
    void f(int);
};
struct i_have_inherited_f : i_have_f
{};

#include <iostream>


template<typename T>
struct must_have_f{
    static_assert(has_f<T>::value,"T doesn't have f");
};

int main()
{
    must_have_f<i_have_f> t0; (void)t0;
    must_have_f<i_have_overloaded_f> t1; (void)t1;
    must_have_f<i_have_inherited_f> t2; (void)t2;
    must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
    must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
    must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
    must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
    must_have_f<int> t7; (void)t7; // static_assert fails
    return 0;
}

(clang 3.2、gcc 4.7.2/4.8.1 でビルド)

于 2013-06-08T08:12:15.563 に答える
0

これは、質問への回答と問題の解決策の提供との間の微妙な境界線ですが、質問への直接の回答ではありませんが、これは役立つと思います。

背景については、この質問をご覧ください。著者は、Boost のソリューションが気に入らなかったと述べており、そこで提案されたソリューションも特に好きではありませんでした。serialize(object, ostream)オブジェクトをシリアル化するために呼び出すクイック&ダーティなシリアル化ライブラリ(Pythonのマーシャルを考えてください)を書いていました。私は、この関数呼び出しを次の 4 つのいずれかにする必要があることに気付きました。

  1. 普通の古いデータの場合objectは、サイズと生データを書き出すだけです
  2. object独自のメンバー関数 ( ) で作成したクラスの場合、そのメンバー関数object::serializeを呼び出します
  3. その型に特化したテンプレートがある場合は、それを使用してください。
  4. 上記のいずれにも当てはまらない場合は、コンパイル エラーをスローします。シリアル化機能が不適切に使用されています。

コードを書くときは、「トリッキー」な、または一目で理解するのが難しいものを避けるようにしています。このソリューションは、理解するために何時間も熟考しなければならないコードを使用せずに、同じ問題を解決すると思います。

#include <type_traits>
#include <iostream>
#include <vector>
#include <string>

// Template specialization for a POD object
template<typename T> 
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
    os.write((const char*) &out, sizeof(T));
    return os.good();
}

// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T> 
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
    return out.serial(os);
}

// Additional specializations here for common container objects
template<typename T> 
bool serial(const std::vector<T> &out, std::ostream &os)
{
    const size_t vec_size = out.size();

    if(!serial(vec_size, os))
        return false;

    for(size_t i =0; i < out.size(); ++i)
    {
        if(!serial(out[i], os))
            return false;
    }

    return true;
}

class SomeClass
{
    int something;
    std::vector<double> some_numbers;

    ...

    bool serial(std::ostream &os)
    {
        return serial(something, os) && serial(some_numbers, os);
    }
};

ニーズを単純な一連のルールにまとめることができ、一般的ではない解決策で対応できる場合、この方法はうまくいくと思います。

于 2013-06-07T22:20:12.993 に答える