const reference と一時オブジェクト

本の虫: rvalue reference 完全解説 で,C++0x で新しく導入される rvalue reference と言う機能とその使用例について,非常に分かりやすく説明されていました.これを読んでいて const の特徴の一つを思い出したので,今回はそれについて.

関数の引数に const を付ける事によるメリットの一つとして,引数が参照型であっても const であれば一時オブジェクトを渡す事ができると言うものがあります.

#include <iostream>

template <class T>
void f(const T& x) {
    std::cout << x << std::endl;
}

template <class T>
void g(T& x) {
    std::cout << x << std::endl;
}

int main(int argc, char* argv[]) {
    int a = 5;
    
    f(a); // OK
    g(a); // OK
    
    f(a / 2.0); // OK
    g(a / 2.0); // NG!
    
    return 0;
}

上記のコードは,f(a / 2.0); は通りますが g(a / 2.0); はコンパイルエラーとなります.「何らかの関数の結果を別の関数に渡す(f(g(x)); のような形)」のように,関数の引数に一時オブジェクトを指定すると言うコードは意外と頻繁に書く機会があるので,この観点からも(自分で関数やメソッドを定義する際には)引数の const の有無には注意を払った方が良いと言えます.

一時オブジェクトが指定できる事がメリットになる例の一つとして,std::string が引数に指定されている場合があるでしょうか.

#include <iostream>
#include <string>

void f(const std::string& x) {
    std::cout << x << std::endl;
}

void g(std::string& x) {
    std::cout << x << std::endl;
}

int main(int argc, char* argv[]) {
    f("Hello, world!"); // OK
    g("Hello, world!"); // NG!
    return 0;
}

std::string を引数に取る関数に文字列リテラルを指定した場合,暗黙の型変換により std::string の一時オブジェクトが生成されます.この際に,関数の引数が const 参照型であれば一時オブジェクトを受け取ることができますが,const がない場合はコンパイルエラーとなります.