передача std :: ispunct в качестве аргумента в remove_copy_if () не компилируется - PullRequest
0 голосов
/ 23 октября 2019

Я попытался передать std::ispunct в качестве последнего аргумента remove_copy_if и обнаружил, что его не удалось скомпилировать. Однако, если я передаю ispunct (только с удаленным std::), программа компилируется и запускается, как и ожидалось.

код:

#include<iostream>
#include<map>
#include<cctype>
#include<algorithm>
#include<iterator>

using std::map;
using std::string;

string strip_punct(const string &s) {
    string target;
    remove_copy_if(s.begin(), s.end(), std::back_inserter(target), std::ispunct);
    return target;
}

int main() {
    string word = "abc.";
    string target = strip_punct(word);
    std::cout << "target: " << target << "\n";
    return 0;
}

сообщение об ошибке:

$ g++ --std=c++11 -o problem_11_4.out problem_11_4.cpp
problem_11_4.cpp: In function 'std::string strip_punct(const string&)':
problem_11_4.cpp:12:80: error: no matching function for call to 'remove_copy_if(std::__cxx11::basic_string<char>::const_iterator, std::__cxx11::basic_string<char>::const_iterator, std::back_insert_iterator<std::__cxx11::basic_string<char> >, <unresolved overloaded function type>)'
   12 |     remove_copy_if(s.begin(), s.end(), std::back_inserter(target), std::ispunct);
      |                                                                                ^
In file included from /usr/local/Cellar/gcc/9.2.0_1/include/c++/9.2.0/algorithm:62,
                 from problem_11_4.cpp:4:
/usr/local/Cellar/gcc/9.2.0_1/include/c++/9.2.0/bits/stl_algo.h:703:5: note: candidate: 'template<class _IIter, class _OIter, class _Predicate> _OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate)'
  703 |     remove_copy_if(_InputIterator __first, _InputIterator __last,
      |     ^~~~~~~~~~~~~~
/usr/local/Cellar/gcc/9.2.0_1/include/c++/9.2.0/bits/stl_algo.h:703:5: note:   template argument deduction/substitution failed:
problem_11_4.cpp:12:80: note:   couldn't deduce template parameter '_Predicate'
   12 |     remove_copy_if(s.begin(), s.end(), std::back_inserter(target), std::ispunct);
      |                                                                                ^

Я искал на SO и нашел этот вопрос: Почему std :: не нужен при использовании ispunct () в C ++? Это полезно, теперь я знаю, что ispunct можно использовать без std::. Тем не менее, я написал другую программу и обнаружил, что ispunct и std::ispunct оба работают хорошо, когда используются отдельно (не в качестве аргумента). Я до сих пор не понимаю, почему std:: не допускается, когда ispunct используется в качестве аргумента.

Ответы [ 2 ]

2 голосов
/ 23 октября 2019

std::ispunct - перегруженная функция. Существует версия в <cctype> и версия в <locale>. Даже если вы не включите <locale>, одно из включений включает перегрузку и приводит к сбою дедукции, поскольку перегруженные функции не могут иметь тип вывода.

Что вы можете сделать, чтобы решитьэто обернуть std::ispunct в лямбду, так как в теле лямбды компилятор может предварительно преобразовать разрешение перегрузки и вызвать правильную функцию. Это дало бы вам

remove_copy_if(s.begin(), 
               s.end(), 
               std::back_inserter(target), 
               [](unsigned char ch){ return std::ispunct(ch); }); // use unsigned char here to stop any possible UB
1 голос
/ 23 октября 2019

Используйте лямбда-выражение вместо указателя функции.

Вот демонстрационная программа:

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <cctype>

std::string strip_punct( const std::string &s ) 
{
    std::string target;
    std::remove_copy_if( std::begin( s ), std::end( s ), 
                         std::back_inserter( target ), 
                         []( unsigned char c ) { return std::ispunct( c ); } );
    return target;
}

int main() 
{
    std::string word = "abc.";

    std::cout << strip_punct( word ) << '\n';

    return 0;
}

Проблема в том, что в C ++ есть две функции ispunct. Одна - это стандартная функция C ispunct() в заголовке <ctype.h>, а другая - стандартная функция C ++ std::ispunct() в заголовке <locale>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...