📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の4版が非表示)
289行目: 289行目:
また、Visual C++では、コンパイルオプションに<code>/permissive-</code>を付加することにより、独自拡張を無効化することもできる。<br>
また、Visual C++では、コンパイルオプションに<code>/permissive-</code>を付加することにより、独自拡張を無効化することもできる。<br>
<br><br>
<br><br>
== メンバ関数テンプレート (メンバテンプレート) ==
==== メンバ関数テンプレートとは ====
クラスのメンバ関数をテンプレート化することができる。<br>
メンバ関数テンプレートには、テンプレートクラスと非テンプレートクラスがある。<br>
<br>
==== 非テンプレートクラスのメンバ関数テンプレート ====
以下の例では、クラスのメンバ関数テンプレートは、テンプレート実引数に指定した型へ<code>static_cast</code>で変換して値を返している。<br>
型変換を実現するために、メンバ関数テンプレートを使用することは多い。<br>
<syntaxhighlight lang="c++">
#include <iostream>
class CSampleClass
{
private:
    double    mValue;
public:
    explicit CSampleClass(double value) : mValue(value)
    {
    }
    template <typename U>
    inline const U GetValue() const
    {
      return static_cast<U>(mValue);
    }
};
int main()
{
    CSampleClass cls(10.5);
    std::cout << cls.GetValue<int>() << std::endl;    // 10
    std::cout << cls.GetValue<double>() << std::endl;  // 10.5
}
</syntaxhighlight>
<br>
なお、メンバ関数テンプレートの実装をクラス外部に記述する場合は、以下のようになる。<br>
<code>template <typename U></code>の箇所が必要な理由は、非クラステンプレートのため、<code><クラス名><T>::</code>ではなく<code><クラス名>::</code>と記述する必要があるからである。<br>
<syntaxhighlight lang="c++">
template <typename U>
const U CSampleClass::GetValue() const
{
    return static_cast<U>(mValue);
}
</syntaxhighlight>
<br>
特定の型のみをそのまま返す場合は、非テンプレートのメンバ関数を定義することもできる。<br>
<syntaxhighlight lang="c++">
#include <iostream>
class CSampleClass
{
private:
    double    mValue;
public:
    explicit CSampleClass(double value) : mValue(value)
    {
    }
    inline double GetValue() const
    {
        return mValue;
    }
    template <typename U>
    inline const U GetValue() const
    {
      return static_cast<U>(mValue);
    }
};
int main()
{
    CSampleClass cls(10.5);
    std::cout << cls.GetValue<int>() << std::endl;  // 10
    std::cout << cls.GetValue() << std::endl;      // 10.5
}
</syntaxhighlight>
<br>
==== テンプレートクラスのメンバ関数テンプレート ====
以下の例では、テンプレートクラス内でメンバ関数テンプレートを使用している。<br>
<syntaxhighlight lang="c++">
#include <iostream>
template <typename T>
class CSampleClass
{
public:
    explicit CSampleClass(const T& value) : mValue(value)
    {}
    inline const T GetValue() const
    {
      return mValue;
    }
    template <typename U>
    inline const U GetValue() const
    {
        return static_cast<U>(GetValue());
    }
private:
    T mValue;
};
int main()
{
    CSampleClass<double> cls(10.5);
    std::cout << cls.GetValue<int>() << std::endl;  // 10
    std::cout << cls.GetValue() << std::endl;      // 10.5
}
</syntaxhighlight>
<br>
ただし、テンプレートクラス外部にメンバ関数テンプレートを定義する場合、<br>
テンプレートクラスのテンプレート仮引数とメンバ関数テンプレートのテンプレート仮引数の両方を記述する必要がある。<br>
<syntaxhighlight lang="c++">
template <typename T, typename U>
const U CSampleClass<T>::GetValue() const
{
    return static_cast<U>(GetValue());
}
</syntaxhighlight>
<br>
==== デフォルトテンプレート実引数 (C++ 11以降) ====
C++ 11以降では、メンバ関数テンプレートのテンプレート仮引数に、デフォルト引数を与えることができる。<br>
<syntaxhighlight lang="c++">
#include <iostream>
class CSampleClass
{
public:
    explicit CSampleClass(double value) : mValue(value)
    {}
    template <typename U = double>
    inline const U GetValue() const
    {
      return static_cast<U>(mValue);
    }
private:
    double    mValue;
};
int main()
{
    CSampleClass cls(10.5);
    std::cout << cls.GetValue<int>() << std::endl;  // 10
    std::cout << cls.GetValue() << std::endl;      // 10.5
}
</syntaxhighlight>
<br>
==== テンプレート変換演算子 ====
変換演算子も、メンバ関数テンプレートにすることができる。<br>
テンプレート変換演算子により、任意の型への型変換が定義できる。<br>
<br>
テンプレート変換演算子は、代入や初期化時の左辺の型により、テンプレート仮引数を推測している。<br>
<syntaxhighlight lang="c++">
#include <iostream>
class CSampleClass
{
private:
    double    mValue;
public:
    explicit CSampleClass(double value) : mValue(value)
    {}
    template <typename T>
    inline operator T() const
    {
      return static_cast<T>(mValue);
    }
};
int main()
{
    CSampleClass cls(123.456);
    int i = fStore;
    double f = fStore;
    std::cout << i << std::endl;  // 123
    std::cout << f << std::endl;  // 123.456
}
</syntaxhighlight>
<br>
テンプレート変換演算子と、非テンプレートの変換演算子を共存させることも可能である。<br>
その場合、一致度が高い変換演算子が優先的に使用されるため、例えば、int型に変換する場合のみ、非テンプレートの変換演算子を使用することもできる。<br>
<br>
==== コンストラクタテンプレート ====
コンストラクタテンプレートは、テンプレートクラスにおいて、異なるテンプレート実引数を与えてインスタンス化したオブジェクトがある時、互いに暗黙的な変換を行うことにある。<br>
<br>
例えば、テンプレートクラスがコピーコンストラクタを定義する時、コピーコンストラクタを渡す場合は、<br>
<code>クラス名<型></code>のオブジェクトを使用して、新たな<code>クラス名<型></code>のオブジェクトを生成することができる。<br>
ただし、テンプレートクラスのテンプレート仮引数Tに当てはめる型が異なる場合は、定義したコピーコンストラクタが使用できずに、コンパイルエラーとなる。<br>
<syntaxhighlight lang="c++">
template <typename T>
class CSampleClass
{
public:
    CSampleClass(const CSampleClass<T>& rhs);
};
int main()
{
    CSampleClass<int>    cls1(10);
    CSampleClass<int>    cls2(cls1);  // OK
    CSampleClass<double> cls3(cls1);  // コンパイルエラー
    return 0;
}
</syntaxhighlight>
<br>
以下の例では、テンプレート仮引数の違いがある場合でも、コンストラクタテンプレートを使用して、同一の型であるように扱っている。<br>
例から分かるように、コンストラクタテンプレートは、メンバ関数テンプレートそのものである。<br>
<br>
メンバ変数をコピーする場合は、U型からT型への型変換が必要になる。<br>
<code>static_cast</code>で変換しているが、U型とT型の関係性が<code>static_cast</code>で変換できない場合は、コンパイルエラーが起きる。<br>
<br>
また、同一テンプレートクラスで型が異なるの場合、かつ、<code>private</code>なメンバをアクセスする必要がある場合、相手をフレンドクラスとして指定する必要がある。<br>
<syntaxhighlight lang="c++">
#include <iostream>
template <typename T>
class CSampleClass
{
    template <typename>
    friend class CSampleClass;
public:
    explicit CSampleClass(const T& value) : mValue(value)
    {}
    // CSampleClass<U> からコピー
    template <typename U>
    CSampleClass(const CSampleClass<U>& rhs) : mValue(static_cast<T>(rhs.mValue))
    {}
    inline const T GetValue() const
    {
      return mValue;
    }
private:
    T    mValue;
};
int main()
{
    CSampleClass<int> cls1(10);
    CSampleClass<double> cls2(cls1);  // OK
    std::cout << cls1.GetValue() << std::endl;  // 10
    std::cout << cls2.GetValue() << std::endl;  // 10.0
}
</syntaxhighlight>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]