-1

以下は、事前定義された数の型のいずれかに変換できるテンプレート引数で機能することを期待する、欠陥のある (そして簡略化された) テンプレート関数です。

たまたま2種類ですが、寒いのはもっと多いです。

void do_something_type_specific( const int &unused ) { std::cout << 'i'; }
void do_something_type_specific( const std::string &unused ) { std::cout << 's'; }

template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    do_something_type_specific( *begin );
    // Perhaps more code...
}

これにより、私の環境で望ましい結果が得られます。*Iteratorテンプレート インスタンスは、選択肢の 1 つに変換可能な型を生成する場合に正常にコンパイルされます。

ただし、このコードは不必要に変換の実行を要求し、使用されていないにもかかわらずunused、まだ UB when begin == end.

これらの問題なしに、この動作を C++03 でどのように実装できますか?

4

4 に答える 4

3

の場合に未定義の動作になるイテレータを逆参照する代わりに、std::iterator_traits<>begin == endを使用してみてください。例えば:

#include <iterator>
#include <string>
#include <cstdio>

void do_something_type_specific(std::string const&) { printf("%s\n", __PRETTY_FUNCTION__); }
void do_something_type_specific(int const&) { printf("%s\n", __PRETTY_FUNCTION__); }

template<class T>
struct ProduceValue
{
    static T value;
};

template<class T>
T ProduceValue<T>::value;

// Specializations for types that can't be default constructed or must be initialized.
template<>
char* ProduceValue<char*>::value = "";

template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    do_something_type_specific(ProduceValue<value_type>::value);
}

int main() {
    char** p = 0;
    perform_work_on_a_range(p, p);

    long* q = 0;
    perform_work_on_a_range(q, q);
}

出力:

void do_something_type_specific(const string&)
void do_something_type_specific(const int&)

唯一の不都合は、ProduceValue<T>デフォルトで構築できない型、または他の理由 ( などchar*) で初期化する必要がある型に特化する必要があることです。

于 2013-03-06T17:00:01.703 に答える
2

boost::is_convertible型 T を他の型 U に変換できるかどうかを判断するために使用できるメタ関数があります。

次に、begin == end実行時チェックを挿入するだけです。

于 2013-03-06T16:52:51.700 に答える
1

問題のあるコードは、テンプレート パラメーター関数パラメーターの両方の機能を活用しようとしています。

関数パラメーターは型変換を許可しますが、型のインスタンス化が必要です。テンプレート パラメーターはインスタンス化する必要はありませんが、型変換も実行しません。

以下のパターンでは、Boost のenable_ifandis_convertibleを使用して、テンプレート パラメーターが関数パラメーターと同じ型変換規則をサポートしているかのように、コンパイラがテンプレート関数を選択できるようにします。 (提案をありがとう@dhavenith)

#include <boost/utility.hpp>
#include <boost/type_traits.hpp>

// enable_if_c makes the return type either void or a Substitution Failure.
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,int>::value>::type
do_something_type_specific()
{
  std::cout << 'i';
}

template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,std::string>::value>::type
do_something_type_specific()
{
  std::cout << 's';
}

template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    // This code is from @MaximYegorushkin's answer.  Vote him up :)
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    do_something_type_specific<value_type>();
    // Perhaps more code...
}

これは、@MaximYegorushkin のサンプル メインで検証されています。

int main() {
    char** p = 0;
    perform_work_on_a_range(p, p);

    long* q = 0;
    perform_work_on_a_range(q, q);
}

出力:

si
于 2013-03-06T18:52:22.080 に答える
0

代わりに、おそらく次のようなことをしたいと思うでしょう:

template <typename T>
void do_something_type_specific() {}
template <>
void do_something_type_specific<int>() {...}
template <typename Iterator>
void perform_work_on_a_range(Iterator begin, Iterator end) {
    do_something_type_specific<typename Iterator::value_type>();
}
于 2013-03-06T17:24:53.087 に答える