39

C++で一般的な方法で何かを実装する方法がわかりません。少し複雑なので、少しずつ説明させていただきます。


そのようなコードを考えてみましょう:

void a(int) {
    // do something
}
void b(int) {
    // something else
}


void function1() {
    a(123);
    a(456);
}
void function2() {
    b(123);
    b(456);
}

void test() {
    function1();
    function2();
}

簡単に気付くことができますが、同じことfunction1function2行いますが、唯一の異なる部分は内部機能です。

functionしたがって、コードの冗長性を回避するために汎用的にしたいと思います。関数ポインタまたはテンプレートを使用してそれを行うことができます。とりあえず後者を選びましょう。私の考えでは、コンパイラーは確実に関数をインライン化できるので、より良いと思います-私は正しいですか?関数ポインターを介して呼び出された場合でも、コンパイラーは呼び出しをインライン化できますか?これは副次的な質問です。

OK、元のポイントに戻ります...テンプレートを使用したソリューション:

void a(int) {
    // do something
}
void b(int) {
    // something else
}

template<void (*param)(int) >
void function() {
    param(123);
    param(456);
}

void test() {
    function<a>();
    function<b>();
}

大丈夫。しかし、私は問題に直面しています。ジェネリック自体aである場合でも、それを行うことはできますか?b

template<typename T>
void a(T t) {
   // do something
}

template<typename T>
void b(T t) {
   // something else
}

template< ...param... > // ???
void function() {
    param<SomeType>(someobj);
    param<AnotherType>(someotherobj);
}

void test() {
    function<a>();
    function<b>();
}

テンプレートパラメータは次のいずれかになります。

  • タイプ、
  • テンプレートタイプ、
  • タイプの値。

それらのどれも私の状況をカバーしていないようです。したがって、私の主な質問は、それをどのように解決するか、つまり function()最後の例で定義するかということです。

(はい、関数ポインターはこの場合の回避策のようです-インライン化することもできます-しかし、私はこのクラスの問題の一般的な解決策を探しています)。

4

4 に答える 4

37

テンプレートでこの問題を解決するには、テンプレートテンプレートパラメータを使用する必要があります。残念ながら、最初にインスタンス化する必要があるため、テンプレートテンプレート関数を型として渡すことはできません。ただし、ダミー構造の回避策があります。次に例を示します。

template <typename T>
struct a {

    static void foo (T = T ())
    {
    }

};

template <typename T>
struct b {

    static void foo (T = T ())
    {
    }

};

struct SomeObj {};
struct SomeOtherObj {};

template <template <typename P> class T>
void function ()
{
    T<SomeObj>::foo ();
    T<SomeOtherObj>::foo ();
}

int main ()
{
    function<a>();
    function<b>();
}
于 2011-01-15T00:42:11.953 に答える
4

C ++ 14の汎用ラムダを使用すると、次のことが可能になります。

template<typename T> void a(T t) { /* do something */}
template<typename T> void b(T t) { /* something else */ }

template <typename F>
void function(F&& f) {
    f(someobj);
    f(someotherobj);
}

void test() {
    // For simple cases, auto&& is even probably auto or const auto&
    function([](auto&& t){ a(t); });
    function([](auto&& t){ b(t); });

    // For perfect forwarding
    function([](auto&& t){ a(std::forward<decltype(t)>(t)); });
    function([](auto&& t){ b(std::forward<decltype(t)>(t)); });
}

関数ポインターを介して呼び出された場合でも、コンパイラーは呼び出しをインライン化できますか?

可能ですが、実際にはもっと複雑で、ファンクターやテンプレートよりも頻繁に失敗する可能性があります。

于 2019-05-31T17:21:55.957 に答える
0

これが方法です。最善ではないかもしれませんが、機能します。

template <typename T, T param>
void function() {
    param(123);
    param(456);
}

void test()
{
    function< void(*)(int), a<int> >(); // space at end necessary to compiler
    function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous
}

インライン化されるかどうかはコンパイラーによって異なりますが、インライン化されていない場合はかなり驚きます。

編集:さて、私は今日少し離れていて、パラメータが異なるタイプである部分を逃しました。私の悪い。

テンプレートを使用してこれを行うには注意が必要な方法があるかもしれませんが、これは私が考えることができる最も簡単な方法です。

#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0)

私は知っている、私は知っている、「マクロは悪だ」何とか何とか何とか。できます。あなたfunctionの例よりも複雑にする必要がある場合は、問題が発生する可能性がありますが、私が思いついたものよりもはるかに簡単です。

于 2011-01-15T00:11:41.110 に答える
-1
template < typename F >
void function(F f)
{
  f(123);
}

void a(int x) { ... }

struct b { void operator() (int x) { ... } };

void outer()
{
  function(&a);
  function(b());
}
于 2011-01-15T00:45:56.750 に答える