2017-03-30 25 views
1

私の目標は、の単純な加算を行うことですと、C++での追加を機能限り、彼らは以下の種類があるようなパラメータの任意の数 -可変個引数は、制約のタイプ

  1. 整数(例えば123)

  2. 整数(例:「123」)として表現文字列

彼らは他のいくつかのタイプである場合、私はそれらを無視します。

アプローチ

  1. 私は可変引数関数アプローチを使用しています。
  2. この関数内では、型をチェックします。タイプがの場合、の場合、再帰的に追加します。そうでなければ、私は議論を無視し、さらに議論を繰り返す。私は私のことを教えて観測を次なさ、しかし

    :これは私に期待される答えを与える

    // BASE 
    template <typename T> 
    int func(T t) 
    { 
        string type= typeid(t).name(); 
        if (type==typeid(int).name()) 
         return stoi(t); 
        else if (type==typeid(const char*).name()) 
         return atoi(t); 
        else 
         return 0; 
    } 
    // RECUR 
    template<typename T, typename... Args> 
    int func(T t, Args... args) // recursive variadic function 
    { 
        string type = typeid(t).name(); 
        if (type==typeid(int).name()){ 
         int sum = t; 
         return sum+func(args...); 
        } 
        else 
         return func(args...); 
    
    } 
    
    // MAIN 
    int main() 
    { 
        // All testing here in MAIN. 
    
    
        // [2] 
        int funcres = func('a',1, 2.5000,"123"); 
        cout << funcres << endl; 
    
        return 0; 
    } 
    

    から

は、ここで私は、コードがどのように見えると思うものですコードはフェールセーフではありません。

  • なぜこの基本機能の行には必須ですか?

    if(type == typeid(int).name()) return stoi(t);私はこれを行うと、ちょうどreturn tを呼び出さない場合、私は私の関数を呼び出すとき

、私はエラーを取得します。

Cannot initialize return object of type 'int' with an lvalue of type 'const char *' 

タイプが整数の場合は整数を返します。これはすでに指定している場合は意味がありません。

  • 私は何でも後return stoi(t)タイプは、その後const char*冒頭で「日本」や「123」挿入された場合return atoi(t)を(私が最初の場所で必要とされる理由を理解していないもの)、およびかテンプレートのargリスト[for.eg func(1,2,2.5000,"123",12);]の中ののは、コードがこの時点で文句を付ける原因となります。

    int sum = t;

エラーは上記と同じです。

Cannot initialize return object of type 'int' with an lvalue of type 'const char *' 
  • 可変引数関数に最善の方法を使用するかの選択肢がありますされていますか?
  • これは最善の方法です(追加するために必要なパラメータと任意の種類のパラメータが必要なので、私にはそう思われます)。何が間違っていますか?
+1

'typeid'を使用すると、コンパイル時に(タイプを比較して)できることが起こります。 'name'を使うことによって、それらが実際に同じ型であることを保証することはできません(異なる型は' name'に対して同じ結果を与えることができます)。コンパイラは、ランタイムブランチを実行した後、そのタイプだけをコンパイル時に使用できるようにする(過負荷解決など)ために変数を使用しようとすると文句を言うでしょう。 'int'も唯一の整数型ではありません。 'long int'はどうですか? 'unsigned int'ですか? 'char'は技術的には整数型なので、一般化すれば除外しなければなりません。 'signed char'? – chris

答えて

1

オーバーロードが1つの可能性である:あなたがそれを暗黙的にintに変換したくない場合はcharが不可欠であるので、我々はまた、0のchar型の過負荷を追加する必要があります。いくつかのテンプレートマジックでそれを行うこともできます。これは、あなたが合計しているリストが、コンパイル時にすべての互換性のない型(最後の要素を除いて、整形されていない場合は0で置換されます)から整理されるという利点があります。

#include <cassert> 
#include <string> 
#include <type_traits> 


template < typename T > 
struct is_const_char : std::false_type {}; 
template < > 
struct is_const_char < const char * > : std::true_type {}; 

template < typename T > 
struct is_int : std::false_type {}; 
template < > 
struct is_int <int> : std::true_type {}; 


// Break condition 
template < typename T > 
typename std::enable_if<is_int<T>::value, int>::type 
sum(T t) 
{ 
    return t; 
} 

template < typename T > 
typename std::enable_if<is_const_char<T>::value, int>::type 
sum(T t) 
{ 
    return std::stoi(t); 
} 

template < typename T > 
typename std::enable_if<!is_int<T>::value && !is_const_char<T>::value, int>::type 
sum(T) 
{ 
    return 0; 
} 


// Forward declarations 
template < typename T, typename ... Args > 
typename std::enable_if<is_const_char<T>::value, int>::type 
sum(T, Args ...); 

template < typename T, typename ... Args > 
typename std::enable_if<is_int<T>::value, int>::type 
sum(T, Args ...); 

// Recursions 
template < typename T, typename ... Args > 
typename std::enable_if<!is_int<T>::value && !is_const_char<T>::value, int>::type 
sum(T, Args ... args) 
{ 
    return sum(args...); 
} 

template < typename T, typename ... Args > 
typename std::enable_if<is_int<T>::value, int>::type 
sum(T t, Args ... args) 
{ 
    return t + sum(args...); 
} 

template < typename T, typename ... Args > 
typename std::enable_if<is_const_char<T>::value, int>::type 
sum(T t, Args ... args) 
{ 
    return std::stoi(t) + sum(args...); 
} 


// Test it 
int main() 
{ 
    assert(sum('a', 1, 2, 3, "123", 4, 5) == 138); 
    assert(sum('a',1, 2.5000,"123") == 124); 
} 
2

C++テンプレートは静的に解決されます。つまり、実行時に到達不能なものであっても、パラメータの置換はすべての置換に対して機能する必要があります。あなたは単純な再帰合計を行うことができ、このヘルパー関数で

template<class T> 
int forceInt(T arg) { return 0; } 

int forceInt(int arg) { return arg; } 

int forceInt(std::string arg) { return std::stoi(arg); } 

int forceInt(const char * arg) { return std::stoi(arg); } 

int func() { return 0; } 

template<typename T, typename... Args> 
int func(T t, Args... args) // recursive variadic function 
{ 

     return forceInt(t) + func(args...); 
} 

このことができますまた、しかし、我々はより多くのきれいな変換を扱うことができるヘルパー関数をオーバーロードを使用しての代わりに、RTTIにより、任意の整数型を扱うように拡張することができます。一般的なオーバーロードでSFINAEを使用して非整数型に制限すると、int型オーバーロードが整数型に優先されます。

template<class T, class U = typename std::enable_if<!std::is_integral<T>::value>::type> 
int forceInt(T arg) { return 0; } 

int forceInt(char arg) {return 0;} 
+0

オーバーロードを提供するのではなく、あなたが 'forceInt'をどのように特化したか興味深いですが、専門化する代わりに' func'のオーバーロードを提供しました。 – chris

+0

Yehは、テンプレートよりも具体的なオーバーロードが選択されているのを忘れています。過負荷は多くのクリーナーです。 – user1937198

+0

オーバーロード解決を利用するとランタイムコストもゼロになります。 –

関連する問題