Определить, какие аргументы командной строки числовых


Я работаю над использованием STL и в целом безопасная практика с++. Вместо размещения крупных образцов кода я работаю с небольшой образец, чтобы поймать проблемы, перед тем как перейти на более крупные.

Как вы узнаете если istringstream нашел вход, который не нужного типа? То есть, у вас есть строка, и вы хотите, чтобы проверить, если это поплавок или нет.

С помощью программы ниже, когда я ввожу

[mehoggan@desktop argument_processing]$ ./args 1 2 3 4 2y

Я получаю:

1 2 3 4 2 

это не то, чего я хочу, так как не все аргументы, где числовые.

Я должен был отдать:

ERROR: 2y is not numeric

Какие улучшения вы могли бы сделать для этой маленькой программы?

#include <vector>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <iterator>

namespace CLP {
    using std::vector;
    using std::istringstream;
    using std::string;
    using std::cerr;
    using std::endl;

    vector<float> all_numeric_arguments( int argc, char *argv[ ] ) {
        vector<float> v_argv;
        vector<string> v_tmp;
        copy( &argv[1],&argv[argc],back_inserter( v_tmp ) );
        for( vector<string>::iterator it=v_tmp.begin( );it!=v_tmp.end( );it++ ) {
            istringstream iss( (*it) );
            float f=0.0;
            if( iss >> f >> std::dec ) {
                v_argv.push_back( f );
            } else {
               cerr << "ERROR: " << (*it) << " is not numeric " << endl;
               return v_argv;
            }
        }
        return v_argv;
    }
}

int main( int argc, char *argv[ ] ) {
    std::vector<float> v = CLP::all_numeric_arguments( argc, argv );
    if( v.size( ) == (unsigned)(argc-1) ) {
        copy( v.begin( ),v.end( ),std::ostream_iterator<float>( std::cout," " ) );
        std::cout << std::endl;
    }
}


353
6
задан 4 августа 2011 в 05:08 Источник Поделиться
Комментарии
2 ответа

В вашем случае, вы, видимо, хотите убедиться, что там была не только успешной конверсии, но также, что преобразование потребляемой все входные. Учитывая, что это именно то, что толчок lexical_cast делает, мой непосредственный совет будет использовать свой существующий код, чтобы сделать работу. Если вы не можете сделать это, я бы все-таки написать подобную функцию, и, вероятно, дать ему такое же название, поэтому люди, которые уже знают о lexical_cast сможете признать то, что ты делаешь без того, чтобы читать код, чтобы сделать это.

Что касается других перемен, а не с помощью функции std::копировать , чтобы скопировать агду в v_tmp, я бы, наверное, просто инициализировать v_tmp из агду. Я бы также отметила, что &х[г] , Как правило, эквивалентно х+г, и упростить, что часть кода немного, давая:

std::vector<string> v_tmp(argv+1, argv+argc);

Это дает нам код, который выглядит так:

template<typename Target, typename Source>
Target lexical_cast(const Source& arg) {
// ...
}

std::vector<string> v_tmp(argv+1, argv+argc);
vector<float> v_argv;

for (int i=0; i<v_tmp.size(); i++)
v_argv.push_back(lexical_cast<float>(v_tmp[i]);

Остается один реальный вопрос, однако: как именно вы хотите, чтобы сигнализировать о том, что ваш lexical_cast не удалось. Повысить lexical_cast бросает исключение. Одной из возможных альтернатив для того, что бы вернуть Нэн. Я вовсе не уверен, что я бы рекомендовал, но я могу представить ситуации, где это может быть предпочтительным способом пойти.

Предполагая, что вы идти по пути исключения, то код будет что-то вроде этого:

for (int i=0; i<v_tmp.size(); i++) {
try {
v_argv.push_back(lexical_cast<float>(v_tmp[i]));
}
catch (bad_lexical_cast const &) {
std::cerr << "Error: " << v_tmp[i] << " is not numeric.\n";
}
}

Это оставляет нас с определением lexical_cast себя. Большинство из них было вполне очевидно, по существу идентичен коду у вас, просто добавить проверку, что после того, как мы делаем преобразование, поток пуст:

template<typename Target, typename Source>
Target lexical_cast(const Source& arg) {
istringstream iss(arg);
Target f = Target(); // generic equivalent to your `0.0` initialization

iss >> f;
char c;

// if the conversion failed, or we can read another character, we
// couldn't convert, or there's data left in the stream, which we
// consider a failure.
if (iss.fail() || iss.get(c))
throw bad_lexical_cast();
return f;
}

Так что бросать bad_lexical_cast, мы также должны определить, что тип. В этом случае, мы будем держать его простым:

class bad_lexical_cast {};

В действительности, вы обычно хотите вывести свои исключения классы (напрямую или косвенно) от std::исключение (если вы определили подобной иерархии свое ... в любом случае вы, как правило, нужен общий базовый класс для всех исключений). Возможно, вы также захотите включить указание на то, что не удалось и почему в исключение самого объекта, поэтому код, который ловит это не нужно как можно больше информации о том, что делается в то время, как мы здесь.

7
ответ дан 4 августа 2011 в 02:08 Источник Поделиться

Здесь есть два небольших вопроса по поводу форматирования:


  1. В all_numeric_arguments после введения v_tmp, вы должны позвонить v_tmp.резерв(АГДС); так что вы не будете делать многих перераспределений. (Это чисто для оптимизации, которая, наверное, не важно в данном примере, но поскольку вы знаете размер это хорошая идея.)

  2. В течение цикла, вы должны использовать const_iterators, чтобы дать понять, что вы не измените v_tmp. Также (другой оптимизации, которая просто хорошая привычка) не называй v_tmp неоднократно.

    Так что Ваши для петли следует читать так:

    for( vector<string>::const_iterator it = v_tmp.begin(),
    end = v_tmp.end();
    it != end ; ++it )
    {
    //...
    }

    или если вы можете использовать C++0х:

    for (auto it = v_tmp.cbegin(), end = v_tmp.cend(); it != end; ++it) { /* ... */ }

4
ответ дан 4 августа 2011 в 09:08 Источник Поделиться