プログラム系統備忘録ブログ

記事中のコードは自己責任の下でご自由にどうぞ。

C++/CLIでの文字列リテラルの扱い

VisualStudio2012で確認。
検索してみると次のページがヒットしました。

これらのページを参考に、以下のサンプルコードを書いて確認してみました。出力を行うメソッドの出力内容は、右にコメントで記述しています。

#include<stdio.h>
#include<typeinfo>
#include<msclr/marshal.h>
using namespace System;

void OverloadedFunc(const char*){
    puts("const char *を受け取りました");
}
void OverloadedFunc(char*){
    puts("char *を受け取りました");
}
void OverloadedFunc (String^){
    Console::WriteLine("Sytem::String ^を受け取りました");
}

template<typename T>
void TemplateFunc(T){
    puts(typeid(T).name());
}
generic<typename T>
void GenricFunc(T){
    Console::WriteLine(T::typeid);
}

int main(){
    String ^s1 = "abc"; // 文字列リテラルからは暗黙にString^に変換可能
    String ^s2 = L"あいう";    // ワイド文字列リテラルからも暗黙に変換可能
    Uri ^uri = gcnew Uri("http://www.google.co.jp");    // String^を引数とするものも呼び出せる
    Object ^obj = "abc";    // String^に暗黙に変換され、Object^にアップキャストされる
    Console::WriteLine(obj::typeid);    // "System.String"

    char *cStr = "abc"; // C++のポインタ型経由
    // String ^errorStr = cStr; // charポインタ及びchar配列からはconstであったとしても、String^の暗黙的な変換はない
    String ^s3 = gcnew String(cStr);    // Stringのコンストラクタを通すと変換可能
    String ^s4 = ::msclr::interop::marshal_as<String^>(cStr);   // marshalを使っても変換可能

    puts(typeid("abc").name());   // "char const [4]"
    puts(typeid("abc"-0).name());   // "char const [4]"
    // puts(typeid("abc"+0).name());   // コンパイルエラー
    auto s = ("abc"+0); // 一時変数を媒介せずにtypeidを使う方法がわかりませんでした
    Console::WriteLine(s::typeid);  // "System.String"
    Console::WriteLine("abc"+0);    // "abc0";

    // Console::WriteLine("abc"->Length);  // ->入力後インテリセンスが働くのに、コンパイルエラーとなる

    OverloadedFunc("abc");    // "Sytem::String^を受け取りました"
    OverloadedFunc(L"あいう");   // "Sytem::String^を受け取りました"
    TemplateFunc("abc");    // "char const *"
    GenricFunc("abc");  // "System.String"

    return 0;
}

加法演算子+を文字列リテラルに対して適応した場合、注意が必要となりそうです。

しかしまあ、インテリセンスの候補として表示されるものがコンパイルエラーとなるのは混乱の元になりかねないような・・・。
上記コードのs::typeid行にて「'::typeid' が後に続く名前は型名である必要があります」と言ってきましたが実行可能ですし・・・。