0

私は次のsmart_ptrクラスを持っています。

template <typename T>
class smart_ptr
{
public:
    // ... removed other member functions for simplicity
    T* get() { return ptr; }

    template <typename... Args>
    decltype(T::template operator ()(Args()...)) operator ()(Args... args) const
    {
        return (*get()).operator ()(args...);
    }

private:
    T* ptr;
};

ただし、smart_ptrなしで型 T のクラスを使用するoperator ()と、コンパイルに失敗します (当然のことです)。

私が欲しかったのはstd::enable_if、 T が を持っている場合にのみメンバー関数を有効にするために使用することoperator ()です。SFINAE を使用して T が持っているかどうかを検出しoperator ()、それを組み合わせてstd::enable_if必要なものを取得することを考えていたので、それを始めたとき、それは非常に急速に曖昧で複雑になりました。ただし、可変個引数テンプレートoperator ()を検出できる SFINAE の作成に迷いました(つまりIs it possible to write a template to check for a function's exists?の複製ではありません)。

誰でも助けることができますか?または、別の(おそらくもっと簡単な)解決策を教えてください。

ps GCC 4.5.3で動作する必要があります。

編集:完全を期すために、GCC 4.5.3 の実用的なソリューションで自分の質問に答えました。

4

2 に答える 2

2

編集済み:実際の解決策を提供しなかった元の回答とは完全に異なります。

このコードは、gcc 4.5.1 を使用する ideone でコンパイルされました。それは私ができる最善のことです。

#include <array>
#include <iostream>

using namespace std;

template<typename T>
struct has_property
{
    struct UnmentionableType { UnmentionableType() {} };

    //test if type has operator() (...)
    template<typename U, typename A1, typename A2, typename A3, typename A4, typename A5>
    static auto ftest(U* t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> decltype((*t)(a1, a2, a3, a4, a5), char(0));
    static std::array<char, 2> ftest(...);

public:
    static const bool value = sizeof(ftest((T*)0, UnmentionableType(), UnmentionableType(), UnmentionableType(), UnmentionableType(), UnmentionableType())) == 1;
};

class c1
{
public:
    int operator() () {  return 0; }
};

class c2
{
public:
    void operator() (int) { }
};

class c3
{
public:
    template<typename... Args>
    void operator() (Args... a) { }
};

class c4
{
public:
    template<typename T>
    void operator() (T t) { }
};

int main()
{
    cout<<boolalpha<<has_property<c1>::value<<endl;
    cout<<boolalpha<<has_property<c2>::value<<endl;
    cout<<boolalpha<<has_property<c3>::value<<endl;
    cout<<boolalpha<<has_property<c4>::value<<endl;
}

出力:

false
false
true
false

ノート:

1) 要求に応じて、可変個引数のテンプレート化された operator() でのみトリガーされます (ほぼ)

2)「完璧な」解決策ではありませんが、実用には十分なはずです。

残念ながら、gcc 4.5.1 はパラメーター パックを展開できません。私はこれがあなたのために働くかもしれないと思う:

template<typename U, typename... A>
static auto ftest(U* t, A... a) -> decltype((*t)(a...), char(0));

5 つ (またはそれ以上) のランダム型パラメーターを渡すのではなく、関数の真の可変性を実際にテストする方法はまだわかりません。

with_enable if の使用法 - 部分的なクラスの特殊化以外の解決策はありません。

//non-specialized
template<typename T, typename E=void>
class container
{
    T* ptr;

public:
    T* get() { return ptr; }
};

//specialization for class with appropriate operator()
template<typename T>
class container<T, typename std::enable_if<has_property<T>::value, void>::type>
{
    T* ptr;

public:
    T* get() { return ptr; }

    template <typename... Args>
    decltype(T::template operator ()(Args()...)) operator ()(Args... args) const
    {
        return (*get()).operator ()(args...);
    }
};
于 2012-11-27T23:35:57.677 に答える
1

最後に、GCC 4.5.3 の回避策を見つけました!

template <typename T>
class smart_ptr
{
public:
    // ... removed other member functions for simplicity
    T* get() const { return ptr; }

private:
    template <typename... Args>
    struct opparen_constret
    {
        typedef decltype(std::declval<T const>()(std::declval<Args>()...)) type;
    };

    template <typename... Args>
    struct opparen_ret
    {
        typedef decltype(std::declval<T>()(std::declval<Args>()...)) type;
    };

public:
    template <typename... Args>
    typename opparen_constret<Args...>::type operator ()(Args... args) const
    {
        return (*get())(args...);
    }

    template <typename... Args>
    typename opparen_ret<Args...>::type operator ()(Args... args)
    {
        return (*get())(args...);
    }

private:
    T* ptr;
};
于 2012-11-28T01:48:31.860 に答える