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

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

新規登録して質問してみよう
ただいま回答率
85.48%
メタプログラミング

メタプログラミングとは、プログラミング技法の一つ。プログラムをプログラミングすることを指します。他のプログラムや、そのプログラム自体を操作・出力するメタプログラムを記述する作業をメタプログラミングと呼びます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

585閲覧

variadicなクラステンプレートをテンプレート引数にもつ関数に制約をかけたい

fluid_love

総合スコア21

メタプログラミング

メタプログラミングとは、プログラミング技法の一つ。プログラムをプログラミングすることを指します。他のプログラムや、そのプログラム自体を操作・出力するメタプログラムを記述する作業をメタプログラミングと呼びます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/04/21 07:30

編集2021/04/21 07:31

質問

可変なテンプレートを用いたclass Aを定義します.
そのclass Aをテンプレート引数として受け付ける関数fooを定義します.

このfooのtemplate引数をclass Aのみを受けつけるように制約したいです.

cpp

1 2template<typename ...T> 3class A {}; 4 5template<typename T>//このTはclass Aしか受け付けないようにしたい.class A<ここは何でも大丈夫> 6void foo() { 7 8} 9 10int main() { 11 foo<A<>>();//ok 12 foo<A<int>>()//ok 13 foo<A<int,int,int>>();//ok class Aであれば引数は何でもok 14 //foo<int>();//これはerrorにしたい.fooのテンプレート引数Tがclass Aではないため. 15} 16 17

試したこと

私が考えたのは次のような感じです.

まず,名前空間detailを作り用意に名前空間にアクセスされないようにします.
そしてclass Aclass Emptyをpublicで継承させます.

cpp

1 2namespace detail { 3 class Empty { 4 5 }; 6} 7 8 9template<typename ...T> 10class A : public detail::Empty { 11 12}; 13 14

次に関数fooにてTclass Emptyと継承関係にあるかをチェックします.

cpp

1 2template<typename T> 3void foo() { 4 static_assert(std::derived_from<T,detail::Empty>,"関数fooのtemplate引数ははclass Aのみ受け付けます."); 5 6} 7 8///もしくは 9template<typename T> 10concept DerivedFromEmpty = std::derived_from<T,detail::Empty>; 11 12template<DerivedFromEmpty T> 13void foo() { 14 15}

こうすることによって,多少の抜け穴はあるものの目的が達成されました.

cpp

1 2 3namespace detail { 4 class Empty { 5 6 }; 7} 8 9 10template<typename ...T> 11class A : public detail::Empty { 12 13}; 14 15template<typename T> 16void foo() { 17 static_assert(std::derived_from<T, detail::Empty>, "関数fooのtemplate引数ははclass Aのみ受け付けます."); 18 19} 20 21int main() { 22 foo<A<>>(); 23 //foo<int>();//error 24} 25 26 27

さらにEmptyのコンストラクタをprotectedにするとclass Emptyを直接呼び出すミスもなくせるとは思います.(また,コピーコンストラクタやムーブコンストラクタを削除)


また,template<template<typename ...T> typename U>このあたりの技術でなんとかしようと思ったのですが,無理でした.

問題点

できたはできたのですが,懸念点がいくつかありもっと簡潔でスマートな方法があるのではと考えてしまいます.

↓懸念点


  • あまり美しくない(あくまで主観ですが)

もっと次のコードのように簡潔に記述したいです.

cpp

1 2//こんな感じや 3template<typename T> 4void foo(){ 5 static_assert(is_ほにゃらら_v<T>); 6} 7 8//こんな感じ(実際には文法エラー) 9template<typename ...U> 10template<A<...> T> 11void foo(){ 12 13}

  • Emptyクラスを使いまわせないので,他に同様の制約をかけようとするともう一個のEmptyクラスを定義する必要がでてきます.

cpp

1 2namespace detail { 3 class Empty { 4 5 }; 6 7 class Empty2 { 8 9 }; 10} 11 12 13template<typename ...T> 14class A : public detail::Empty {}; 15 16template<typename ...T> 17class B : public detail::Empty2 {}; 18 19template<typename T> 20void foo() { 21 static_assert(std::derived_from<T, detail::Empty>, "関数fooのtemplate引数ははclass Aのみ受け付けます."); 22} 23 24template<typename T> 25void foo2() { 26 static_assert(std::derived_from<T, detail::Empty2>, "関数foo2のtemplate引数ははclass Bのみ受け付けます."); 27} 28

  • 冗長

上と同じです.


  • 少しコストがかかる(かもしれない)

基底クラスが空であれば最適化で基底クラスのメモリは0になると思われますが,基底クラス(class Empty)のコンストラクタの呼び出しに少しコストがかかるのではないでしょうか(ほんの少しですが)

指定する環境

C++11以上C++20以下でお願いいたします.

その他

  • 情報の追記が必要であればコメント欄に書いてください.
  • 初心者なのであまり難しい内容はわかりません.平易な解説だと助かります.

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ある型がクラステンプレート A のインスタンスであることを判定するメタ関数はこのように定義できます。

cpp

1#include <type_traits> 2 3template<template <class ...> class U, class T> 4class is_instance_of { 5private: 6 template<class V> struct helper : public std::false_type {}; 7 template<class... V> struct helper<U<V...>> : public std::true_type {}; 8public: 9 static constexpr bool value = helper<T>::value; 10};

これを用いれば foo は以下のように定義できます。

cpp

1template<typename ...T> 2class A {}; 3 4template<typename T> 5typename std::enable_if<is_instance_of<A, T>::value>::type foo(void) { 6}

投稿2021/04/21 08:54

編集2021/04/21 08:55
SaitoAtsushi

総合スコア5444

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fluid_love

2021/04/21 11:59

まさに追い求めていたものです. ありがとうございます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問