C++ transform解决G++编译没有匹配函数的问题

一、std::transform简介

定义于头文件 <algorithm>,std::transform在指定的范围内应用于给定的操作,并将结果存储在指定的另一个范围内。

transform用于转换和结合元素

1.1 算法提供两个形式

(1)一元操作

一元操作有4个参数,把源容器的元素转换到目标区,即元素的复制与修改一气呵成。

对于一元操作,将op应用于[first1, last1]范围内的每个元素,并将每个操作返回的值存储在以result开头的范围内。给定的op将被连续调用last1-first1+1次。op可以是函数指针或函数对象或lambda表达式。

template < class InputIterator, class OutputIterator, class UnaryOperator >
      OutputIterator transform ( InputIterator first1,  // 源容器的起始地址
                                InputIterator last1,    // 源容器的终止地址
                                OutputIterator result,  // 目标容器的起始地址
                                UnaryOperator op );     // 函数指针
    // typedef 目标容器元素类型 (*UnaryOperator)(源容器元素类型);

 一元操作:op为要进行操作的一元函数对象或sturct、class。

 (2)二元操作

二元操作的形式有5个实参,将两个源序列中的元素合并,并将结果写入目标区。

对于二元操作,使用[first1, last1]范围内的每个元素作为第一个参数调用binary_op,并以first2开头的范围内的每个元素作为第二个参数调用binary_op,每次调用返回的值都存储在以result开头的范围内。给定的binary_op将被连续调用last1-first1+1次。binary_op可以是函数指针或函数对象或lambda表达式。

   template < class InputIterator1, class InputIterator2,
               class OutputIterator, class BinaryOperator >
      OutputIterator transform ( InputIterator1 first1,     // 源容器1的起始地址
                                InputIterator1 last1,       // 源容器1的终止地址
                                InputIterator2 first2,      // 源容器2的起始地址,元素个数与1相同
                                OutputIterator result,      // 目标容器的起始地址,元素个数与1相同
                                BinaryOperator binary_op ); // 函数指针
    // typedef 目标容器元素类型 (*BinaryOperator)(源容器1元素类型,源容器2元素类型);

 二元操作:op为要进行操作的二元函数对象或sturct、class

 1.2 注意事项

(1)一元操作:源容器和目标容器可以是一个,这样和for_each() 算法一样,可以用来改动“序列内”的元素。

(2)二元操作:

  • 用于将两序列元素结合。
  • 调用者必须保证第二源区有足够的空间,至少拥有和第一区间相同的大小。
  • 必须确保目标区间有足够的空间。

1.3 用于大小写转换

#include <iostream>
#include <string>
#include <cctype>
#include <algorithm>
 
using namespace std;
 
int main()
{
    string s = "Hello World";
    cout << s << endl;
    transform(s.begin(),s.end(),s.begin(),::toupper);//<span style="font-family:'Times New Roman';">::toupper使用定义在全局空间里的</span>to<span style="font-family:'Times New Roman';">upp<span style="font-family:'Times New Roman';">er</span></span>
    cout << s << endl;
    transform(s.begin(),s.end(),s.begin(),::tolower);//<font face="'Times New Roman'">::t<span style="font-family:'Times New Roman';">olo<span style="font-family:'Times New Roman';">wer<span style="font-family:'Times New Roman';">使用</span></span></span></font><span style="font-family:'Times New Roman';">定义在全局空间里的</span>to<span style="font-family:'Times New Roman';">lower</span>
    cout << s << endl;
    return 0;
}

 toupper和tolower在C++中定义分别在std和cctype中,std中toupper的原型为一个二元函数。

 二、应用

用 transform ,以 toupper 函数原位转换字符串为大写,然后转换每个字符为其序数值:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
 
int main()
{
    std::string s("hello");
    std::transform(s.begin(), s.end(), s.begin(),[](unsigned char c) -> unsigned char { return std::toupper(c); });
std::vector<std::size_t> ordinals;
    std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
                   [](unsigned char c) -> std::size_t { return c; });
 std::cout << s << ':';
    for (auto ord : ordinals) {
       std::cout << ' ' << ord;
    }
}

 输出:

HELLO: 72 69 76 76 79

 

三、解决G++编译没有匹配函数的问题

3.1 问题描述

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    string word="hello";
    transform(word.begin(), word.end(), word.begin(), toupper);//转换成大写
    cout<<word<<endl;
    return 0;
}

 在linux gcc编译时,出现 编译没有匹配函数。这里出现错误的原因是Linux将toupper实现为一个宏而不是函数。

windows x86 编译连接成功。

 

 在linux 平台上,使用构建cmake工程编译。

CMakeLists.txt 内容如下:


# 全局变量:CMAKE_SOURCE_DIR CMake的起始目录,即源码的根目录
# 全局变量:PROJECT_NAME 工程的名称
# 全局变量:PROJECT_SOURCE_DIR 工程的源码根目录的完整路径

# 全局变量:构建输出目录。默认的,对于内部构建,此变量的值等于CMAKE_SOURCE_DIR;否则等于构建树的根目录
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)  # ${}语法用于引用变量
# 全局变量:可执行文件的输出路径
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# 全局变量:库文件的输出路径
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# 设置头文件位置
include_directories("${PROJECT_SOURCE_DIR}")
# 设置C++标志位
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# 设置源文件集合
set(SOURCE_FILES main.cpp)
# 添加需要构建的可执行文件,第二个以及后续参数是用于构建此文件的源码文件
add_executable(intellij_taste ${SOURCE_FILES})

 构建目录如下:

 进入build目录下执行cmake ../

执行make,编译错误如下所示:

 

3.2 问题定位

std中toupper的原型为一个二元函数,所以使用std::toupper会报错。

3.3 解决方案

可以使用以下方法解决:

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

using namespace std;

int main() 
{
    string src = "Hello World!";
    string dst;

    transform(src.begin(), src.end(), back_inserter(dst), ::toupper);
    cout << dst << endl;

    transform(src.begin(), src.end(), dst.begin(), ::tolower);
    cout << dst << endl;

    return 0;
 }

 编译成功:

 输出结果正确:

 

方法二:将toupper 使用函数指针

 transform(word.begin(), word.end(), word.begin(), (int (*)(int))toupper);//转换成大写

方法三:

去掉

 using namespace std;

 

 

问题原因是到底使用了 std库中的  toupper,还是cctype 库中的toupper

参考文献:

【1】C++ transformhttps://www.cnblogs.com/balingybj/p/4678880.html

【2】C++/C++11中std::transform的使用:https://blog.csdn.net/fengbingchun/article/details/63252470/

【3】transform函数转换大小写:https://blog.csdn.net/jasonLee_lijiaqi/article/details/78448409

【4】C++/C++11中std::transform的使用:https://blog.csdn.net/lihaidong1991/article/details/96098070

【5】C++ string大小写转换以及transform,tolower,toupper,用法:https://blog.csdn.net/qq_31186409/article/details/50545682

【6】C++11 标准库 第二版

【7】C++ STL中string大小写转换 transform算法中toupper的使用注意事项:https://blog.csdn.net/qq_31186409/article/details/50545682

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值