33

テンプレート推論を使用して、次のことを達成できるようにしたいと思います。

GCPtr<A> ptr1 = GC::Allocate();
GCPtr<B> ptr2 = GC::Allocate();

(私が現在持っているもの)の代わりに:

GCPtr<A> ptr1 = GC::Allocate<A>();
GCPtr<B> ptr2 = GC::Allocate<B>();

私の現在の割り当て関数は次のようになります。

class GC
{
public:
    template <typename T>
    static GCPtr<T> Allocate();
};

<A>これは余分なとをノックオフすることは可能でしょう<B>か?

4

6 に答える 6

34

それはできません。戻り値の型は型推定には関与しません。むしろ、適切なテンプレート シグネチャと既に一致した結果です。それにもかかわらず、次のようにほとんどの用途から隠すことができます。

// helper
template <typename T>
void Allocate( GCPtr<T>& p ) {
   p = GC::Allocate<T>();
}

int main()
{
   GCPtr<A> p = 0;
   Allocate(p);
}

その構文が実際に最初のものよりも良いか悪いかGCPtr<A> p = GC::Allocate<A>()は別の問題です。

PS c++11 では、型宣言の 1 つをスキップできます。

auto p = GC::Allocate<A>();   // p is of type GCPtr<A>
于 2010-04-10T10:14:51.857 に答える
32

私が考えることができる唯一のこと: Allocate を、実際の作業を行うテンプレート化された変換演算子を持つ非テンプレート プロキシ オブジェクトを返す非テンプレートにする:

template <class T>
struct GCPtr
{

};

class Allocator
{
public:
    template <class T>
    operator GCPtr<T>() { return GCPtr<T>(); }
};

class GC
{
public:
    static Allocator Allocate() { return Allocator(); }//could give a call-back pointer?
};

int main()
{
    GCPtr<int> p = GC::Allocate();
}
于 2010-04-10T10:22:23.550 に答える
8

あなたは反対のルートに行くことができます。

最新のコンパイラ(数日でリリースされるはずのMSVC 2010、または現在のバージョンのGCC)を使用していて、C ++0x機能に依存することを気にしない場合:

auto ptr1 = GC::Allocate<A>();
auto ptr2 = GC::Allocate<B>();

右側ではなく、余分なもの<A>を節約できます。<B>:)

于 2010-04-10T11:09:28.530 に答える
4

(この回答は @UncleBens と同じですが、引数を完全転送するため、もう少し一般的です。)

readこれは、入力として文字列を受け取り、目的の戻り値の型に従って解析する、haskell のような言語で非常に便利です。

(これはideone のサンプル コードです。)

まず、foo推定する戻り値の型を持つ関数から始めます。

template<typename Ret>
Ret foo(const char *,int);
template<>
std::string foo<std::string>(const char *s,int) { return s; }
template<>
int         foo<int        >(const char *,int i) { return i; }

文字列を要求すると、最初の引数にある文字列を返します。int を要求すると、2 番目の引数が返されます。

auto_foo次のように使用できる関数を定義できます。

int main() {
        std::string s = auto_foo("hi",5); std::cout << s << std::endl;
        int         i = auto_foo("hi",5); std::cout << i << std::endl;
}

これを機能させるには、関数の引数を一時的に保存し、目的の戻り値の型に変換するよう求められたときに関数を実行するオブジェクトが必要です。

#include<tuple>

template<size_t num_args, typename ...T>
class Foo;
template<typename ...T>
class Foo<2,T...> : public std::tuple<T&&...>
{
public: 
        Foo(T&&... args) :
                std::tuple<T&&...>(std::forward<T>(args)...)
        {}
        template< typename Return >
        operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this)); }
};
template<typename ...T>
class Foo<3,T...> : std::tuple<T&&...>
{
public: 
        Foo(T&&... args) :
                std::tuple<T&&...>(std::forward<T>(args)...)
        {}
        template< typename Return >
        operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this), std::get<2>(*this)); }
};

template<typename ...T>
auto
auto_foo(T&&... args)
        // -> Foo<T&&...> // old, incorrect, code
        -> Foo< sizeof...(T), T&&...> // to count the arguments
{
        return              {std::forward<T>(args)...};
}

また、上記は 2 引数または 3 引数の関数で機能します。それを拡張する方法を理解することは難しくありません。

これは書くべきコードがたくさんあります!これを適用する関数ごとに、これを行うマクロを作成できます。ファイルの先頭に次のようなものがあります。

REGISTER_FUNCTION_FOR_DEDUCED_RETURN_TYPE(foo); // declares
                        // necessary structure and auto_???

そしてauto_foo、プログラムで使用できます。

于 2013-11-08T17:52:38.517 に答える
1

戻り値の型で関数をオーバーロードできないのと同じように、テンプレート推定を行うことはできません。同じ理由で、f() が何かを返すテンプレート/オーバーロードである場合、ここで使用する型は次のとおりです。

f();
于 2010-04-10T10:19:27.293 に答える
0

マクロを使用してみてください。それ以外は、たった1つのステートメントでどのように機能するのかわかりません。

#define ALLOC(ptrname,type) GCPtr<type> ptrname = GC::Allocate<type>()

ALLOC(ptr1,A);

ヨハネスの指摘は有効です。>>の問題は簡単に修正できます。しかし、型の一部としてカンマを使用するには、C99 プリプロセッサの varargs 拡張が必要だと思います。

#define ALLOC(ptrname,...) GCPtr< __VA_ARGS__ > ptrname = GC::Allocate< __VA_ARGS__ >()

ALLOC(ptr1,SomeTemplate<int,short>);
于 2010-04-10T10:15:33.507 に答える