std::stof, std::stod, std::stold

投稿日: Leave a comment

ここにコメント (コメントの仕方がわからずこっちに書きます)

std::stof, std::stod, std::stoldなんてのがC++11にできてたんですね。知りませんでした。これまで、C++で文字列から数値型へ変換するときはboost::lexical_castを使うかstringstreamを使ってました。

試しにVC++2010 (Windows SDK 7.1)で試したらこの関数が使えました。これは便利。

Setting SDK environment relative to C:\Program Files\Microsoft SDKs\Windows\v7.1\.
Targeting Windows 7 x64 Release

C:\work\test>type test_stod.cpp
#include <stdio.h>
#include <string>

int main(int argc, char *argv[])
{
        if (argc > 1) {
                printf("%.16f\n", std::stod(std::string(argv[1])));
        }

        return 0;
}

C:\work\test>cl /EHsc test_stod.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test_stod.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test_stod.exe
test_stod.obj

C:\work\test>test_stod 1.234567890123456789
1.2345678901234567

ところで、Windowsで標準C++ライブラリを使ったコードをコンパイルするときgcc(g++)を使うとlibstdc++のリンクが厄介じゃないですかね?

CとかC++を使うのは、大抵、コンパイルしたEXEファイルを他のPC (スタンドアローンが多い) に移して実行するときなので、ネイティブなコードを作れるVC++かMinGWを使うことになりますが、MinGWのg++はスタティックにリンクすると巨大なexeファイルが出来るし、かといってダイナミックリンクにするとdllを一緒に持ち運ばなければいけないしで、どちらにせよイマイチなので、最近はC++で書いたコードをコンパイルするのはVC++と決めてます。
(Cならgccでも変なバイナリにはならないので、ちょっとしたプログラムはgccを使うこともあります)

Cygwinだとインストーラと一緒に入るからあんまり気にしなくていいのかな。CygwinはWindowsのパス表記とCygwin環境のパス表記の違いが嫌だったり、スタンドアローンなPCに入れるのが面倒なので使ってないです。

lambda式のメモ

投稿日: Leave a comment

無性にC++でlambda式を使ったコードの書き方を知りたくなって、ちょっと調べて書いてみた。

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> v(10);

    int n = 0;
    std::generate(v.begin(), v.end(), [&n]()->int{return n++;});

    std::for_each(v.begin(), v.end(), [](int a){std::cout << a << std::endl;});

    return 0;
}

これは大したコードではなくて、10要素のvector<int>型の配列に0から順にインクリメントした値をセットして、配列の中身をすべて表示するだけのもの。lambda式をgenerateとfor_eachの引数の2か所で使っている。

[&n]()->int{return n++;}

1つ目のこれは、main関数内で宣言したint型の変数n(=0)を返しつつ、呼び出すごとにnをインクリメントするので、呼び出すたびに0, 1, 2, … とインクリメントされた値が返ってくるlambda式(無名関数)。

[&n]のところを[n]にすると、値渡しになって変数nの実体は変更されないので、ずっとゼロが返ってくる。と思ったら、VC++2010だとエラーが出てコンパイルできなかった。

C:\work\test>cl lambda1.cpp /EHsc
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

lambda1.cpp
lambda1.cpp(10) : error C3491: 'n': a by-value capture cannot be modified in a non-mutable lambda

この部分のコードをfor文で書くとこんな感じになるはず。

//std::generate(v.begin(), v.end(), [&n]()->int{return n++;});
for (int i = 0; i < v.size(); i++) {
    v[i] = n++;
}
 [](int a){std::cout << a << std::endl;}

2つめは引数を取るタイプのlambda式。整数を受け取って、iostreamのcoutに流し込んで改行するだけ。

これもfor文で書くとこんな感じになるはず。

//std::for_each(v.begin(), v.end(), [](int a){std::cout << a << std::endl;});
for (int i = 0; i < v.size(); i++) {
    std::cout << a << std::endl;
}

[]と()の違いというか意味を真面目に調べてなかったので全く理解できてなかったけど、書いてみると思ったより簡単だった。

ここで書いたコードだとfor文でイテレータを回す方がコードとしては見やすいようにも思うけど、複雑なコンテナでソートなどの処理するような場合は、lambda式で比較条件式を書いた方がすっきりしそうなので、STLをバリバリ使ってコードを書く場合は役に立ちそう。

参考までに実行結果

C:\work\test>cl lambda1.cpp /EHsc
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

lambda1.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:lambda1.exe
lambda1.obj

C:\work\test>lambda1
0
1
2
3
4
5
6
7
8
9