質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.81%

メタ関数と部分特殊化を同時に使いたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 582

s8079

score 33

前提・実現したいこと

テンプレートの型を整数型に限定したクラスを作り,それを部分特殊化をしたいです.
メタ関数を使うのは初めてですので,使い方を間違っているかもしれません.
よろしくお願いします.

発生している問題・エラーメッセージ

error C2754: 'Hoge<T*,nullptr>': 部分的特殊化は、依存非型テンプレート パラメーターを含むことができません。

該当のソースコード

#include <utility>
template<typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
class Hoge {
    // 省略
};
template<typename T>
class Hoge<T*> {
    // 省略
};
int main() {
    // 省略
    return 0;
}

補足情報(FW/ツールのバージョンなど)

C++11

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

こんにちは。

それは関数テンプレートで部分特殊化的なことを行う時に良く見かける記法のようです。
クラス・テンプレートを定義部分特殊化する時には使えないと思います。

クラス・テンプレートを部分特殊化する時は、必ずプライマリーテンプレートを定義します。その際に最後のテンプレート引数のデフォルト値をvoidにして書くことが多いようです。
そして、部分特殊化テンプレートで、そのデフォルト値を指定したテンプレート・パラメータがvoidになるか、無定義になるように指定します。

#include <iostream>
#include "typename.h"

#include <utility>
template<typename T, class tEnable=void>
class Hoge
{
public:
    Hoge() { std::cout << "[0] T=" << TYPENAME(T) << "\n"; }
};
template<typename T>
class Hoge<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
public:
    Hoge() { std::cout << "[1] T=" << TYPENAME(T) << "\n"; }
};
template<typename T>
class Hoge<T*>
{
public:
    Hoge() { std::cout << "[2] T*=" << TYPENAME(T*) << "\n"; }
};

int main()
{
    Hoge<double> hoge_double;
    Hoge<int> hoge_int;
    Hoge<int*> hoge_intPtr;
    return 0;
}

wandbox

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/01 00:44 編集

    そんな面倒なことしなくても行け~~ますよ~る場合もありますよ(私の回答参照

    キャンセル

  • 2020/02/01 12:24

    あまり普通の使い方ではないかもしれませんが,yumetodoさんのように指定の型以外をエラーにすることは可能でしょうか.
    gccしかコンパイルが通らないのはあまり好ましくありません.

    キャンセル

  • 2020/02/01 14:09

    s8079さん

    単純に下記定義を削除するだけでよいようですよ。
    template<typename T>
    class Hoge<T*> {
    // 省略
    };
    https://wandbox.org/permlink/HtwMkNh3SzomMYW9

    実体化で型を指定した時、その型がenable_if<>の条件に合致しなければ該当のテンプレートが定義されないのでエラーになります。エラー・メッセージは解読困難なので頭痛いですが、それはConceptを待つしか無いと思います。(https://cpprefjp.github.io/lang/cpp20/concepts.html
    ですので、私は見たことはないですが単に私が知らないだけで、これは正当な使い方だろうと思います。

    キャンセル

0

template<typename T>
class Hoge<T*> {
    // 省略
};

template<typename T>
class Hoge<T*, nullptr> {
    // 省略
};

に書き換えることで一応動きますがここで注意があります。

この書き方の場合、std::enable_ifによる制約は特殊化されたほうにも働きます

このため、上記の書き換え後の場合次のようなエラーが出るでしょう。

prog.cc:7:17: error: non-type template argument specializes a template parameter with dependent type 'typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type'
struct Hoge<T*, nullptr> {
                ^
prog.cc:2:96: note: template parameter is declared here
template<typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
prog.cc:2:46: error: failed requirement 'std::is_integral<int *>::value'; 'enable_if' cannot be used to disable this declaration
template<typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:11:39: note: while substituting prior template arguments into non-type template parameter [with T = int *]
static_assert(std::is_same_v<typename Hoge<int*>::type, int>);
                                      ^~~~~~~~~~
prog.cc:11:48: note: while checking a default template argument used here
static_assert(std::is_same_v<typename Hoge<int*>::type, int>);
                                      ~~~~~~~~~^
prog.cc:11:51: error: expected a qualified name after 'typename'
static_assert(std::is_same_v<typename Hoge<int*>::type, int>);
                                                  ^
prog.cc:11:51: error: unknown type name 'type'
4 errors generated.

https://wandbox.org/permlink/fOcgDM7bOiQlRgJR

今回やりたかったのはおそらく整数型へのポインタ型の場合の処理を書きたかったのだと思いますが、それならばChironianさんの書いたような書き方が必要になります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/01 01:10

    おおっ、gccは通りますね。
    でも、clangは通らないようです。
    https://wandbox.org/permlink/p2fenhwHGxnjLeeR

    しかし、プライマリー・テンプレートのenable_ifが成立しない時、その非型パラメータの型はどうなるのでしょう? 関数テンプレートのようにあっさり候補から外れるってわけには行かない筈だから、わからんです。
    ところで、実体化できます? 出来る気がしないです。

    キャンセル

  • 2020/02/01 01:12 編集

    追記しました。制約の働く範囲の問題ですね。全体に掛けていい制約なら私が最初に示したやり方でいけます。
    ちなみにこのnullptrとかいちゃうのは主にこういう制約のあるクラステンプレートを前方宣言するときに便利です。

    キャンセル

  • 2020/02/01 01:20

    あ~、なるほど。
    部分特殊化というよりは、どちらかというと型を制限する時に使える方法なのですね。
    (だって、プライマリー・テンプレートに合致しない型を指定したら、必ずエラーになる筈ですから、一部の型について別定義することはできない筈。)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.81%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る