9

ユーザーのファイルシステムをスキャンし、ベクトルにパスを入力してから、ソートするかどうかの関数があります。ユーザーはベクトルをソートするかどうかをコンパイル時に決定できるはずなので、非常に望ましい (しかし存在しない) "静的 if" の代わりに、テンプレートとヘルパー クラスを使用します。

次のコードを検討してください。

enum class Sort{Alphabetic, Unsorted};  

template<Sort TS> struct SortHelper;
template<> struct SortHelper<Sort::Alphabetic>
{
    static void sort(vector<string>& mTarget) { sort(begin(mTarget), end(mTarget)); }
};
template<> struct SortHelper<Sort::Unsorted>
{
    static void sort(vector<string>&) { }
};

template<Sort TS> struct DoSomethingHelper
{
    static void(vector<string>& mTarget)
    {
         // do something with mTarget
         SortHelper<TS>::sort(mTarget);
    }   
};

私が上で書いたコードは、元のから非常に単純化されており、複数のテンプレート パラメーターを使用して、ユーザーがコンパイル時に関数の結果をさらにカスタマイズできるようにしています。

これらのヘルパー クラスをすべて使用する代わりの方法はありますか? 本当にぐちゃぐちゃで読みにくいです。

理想的には、これは私が書きたいものです:

enum class Sort{Alphabetic, Unsorted};  
template<Sort TS> struct DoSomethingHelper
{
    static void(vector<string>& mTarget)
    {
         // do something with mTarget
         static_if(TS == Sort::Unsorted) { /* do nothing */ }
         static_if(TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); }
    }   
};
4

3 に答える 3

18

あなたの値はコンパイル時に知られているので(非テンプレート型パラメータ)、「通常」を完全に書くことができますif

template<Sort TS>
void someFunction(vector<string>& mTarget)
{
     if (TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); }
     // else if (TS == Sort::Unsorted) {}
}

コンパイラは、定数の折りたたみデッド コードの削除を実行し(もちろん、これらの最適化が有効になっている場合)、結果は仮想の を使用した場合とまったく同じになりますstatic_if

于 2013-06-10T13:20:50.933 に答える
12

の使い方について誤解がありましたstatic_if

確かに、static_if(または実際に望むどんなトリックでも)使用して最適化を試みることができますが、それが最初の目標ではありません。

の最初の目標static_ifセマンティックです。でこれを示しましょうstd::advance。の典型的な実装でstd::advanceは、型スイッチを使用して、コンパイル時に O(1) 実装 (ランダム アクセス イテレータの場合) と O(n) 実装 (その他の場合) を選択します。

template <typename It, typename D>
void advance_impl(It& it, D d, random_access_iterator_tag)
{
    it += d;
}

template <typename It, typename D>
void advance_impl(It& it, D d, bidirectional_iterator_tag)
{
    if (d > D(0)) { for (D i(0); i < d; ++i) { ++it; } }
    else          { for (D i(0); i > d; --i) { --it; } }
}

template <typename It, typename D>
void advance_impl(It& it, D d, input_iterator_tag)
{
    for (D i(0); i < d; ++i) { ++it; }
}

そして最後に:

template <typename It, typename D>
void advance(It& it, D d)
{
    typename std::iterator_traits<It>::iterator_category c;
    advance_impl(it, d, c);
}

ifこの場合、 a だけを使用しないのはなぜですか? コンパイルされないからです。

  • 双方向イテレータはサポートしていません+=
  • 入力反復子 (または前方反復子) はサポートしていません--

したがって、機能を実装する唯一の方法は、指定された型で使用可能な操作のみを使用して関数に静的にディスパッチすることです。

于 2013-06-10T14:27:54.177 に答える
0

テンプレートの特化はどうですか?

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

enum class Sort {
    Alphabetic, 
    Unsorted
};

template<Sort TS> struct DoSomethingHelper {
    static void someFunction(vector<string>& mTarget)
    {}  
};

template<> struct DoSomethingHelper<Sort::Unsorted> {
    static void someFunction(vector<string>& mTarget) {

    }  
};

template<> struct DoSomethingHelper<Sort::Alphabetic> {
    static void someFunction(vector<string>& mTarget) {
        sort(begin(mTarget), end(mTarget));
    }  
};

int main() {
    vector<string> v = {{"foo", "bar", "foo2", "superman", ".."}};

    DoSomethingHelper<Sort::Alphabetic> helper;
    helper.someFunction(v);

    for (string& s : v) {
        cout << s << endl;
    }
    return 0;
}

編集:私はばかです。

于 2013-06-10T20:03:35.107 に答える