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

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

新規登録して質問してみよう
ただいま回答率
85.35%
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

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

Q&A

解決済

1回答

2146閲覧

vectorやarrayなどの一次元配列/二次元配列SFINAE判断条件

退会済みユーザー

退会済みユーザー

総合スコア0

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

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

1グッド

0クリップ

投稿2020/03/22 09:58

編集2020/03/22 10:00

vectorやarrayなどを気にせず標準出力がしたく、以下のようなコードを記述しました。

cpp

1// 一次元配列用(のつもり) 2// 二次元配列でも該当してしまう 3template <typename T> 4auto f(T&& range) -> decltype(std::begin(range), std::end(range), range.back(), void()) { 5 for (const auto& r : range) { 6 if (&r != &range.back()) std::cout << r << " "; 7 else std::cout << r << std::endl; 8 } 9} 10 11// 二次元配列用 12template <typename T> 13auto f(T&& range) -> decltype(std::begin(range), std::end(range), range.back(), std::begin(range.at(0)), std::end(range.at(0)), range.at(0).back(), void()) { 14 for (const auto& r : range) { 15 for (const auto& a : r) { 16 if (&a != &r.back()) std::cout << a << " "; 17 else std::cout << a << std::endl; 18 } 19 } 20} 21 22int main() { 23 std::vector<int> vec(3, 99); 24 f(vec); 25 std::array<int, 4> arr{99, 99, 99, 99}; 26 f(arr); 27 //std::vector<std::vector<int>> vec2(3, vec); 28 //f(vec2); 29 return 0; 30}

以上のコードでfに二次元配列を渡すと複数当てはまってしまいます。
うまく失敗させる方法はありますか?

Paalon👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。

関数テンプレートは、クラス・テンプレートと異なり「プライマリー・テンプレート」がないのでテンプレート間の優先順位は(あまり)ついていません。ですので、基本的には厳密に判定させる必要があります。
つまり、1次元配列は「指定の型が配列で、その要素が配列でない」、多次元配列は「指定の型が配列で、その要素も配列である」を指定する必要があります。

ですので、ご希望の実装のためには、is_containerのようなメタ処理を記述し、enabler方式で関数テンプレートの合致条件を記述するのが良いと思います。

投稿2020/03/22 10:49

Chironian

総合スコア23272

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

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

退会済みユーザー

退会済みユーザー

2020/03/22 16:45

ご丁寧な回答ありがとうございました。回答いただいた記述で実現できそうです。ありがとうございました。
退会済みユーザー

退会済みユーザー

2020/03/23 11:35

再度すみません。 > 1次元配列は「指定の型が配列で、その要素が配列でない」、多次元配列は「指定の型が配列で、その要素も配列である」を指定する必要があります。 をずっと考えていたのですが、なかなか思いつかないです。 作成したis_containerにうまく記述すればできそうではあるのですが… なにかいい方法があればご教示いただきたいです。
Chironian

2020/03/23 13:51

std::is_unsigned<T>はture_type, false_typeを継承しているので、bool型への暗黙の型変換を持っています。そして、std::is_unsigned<T>のインスタンスであるstd::is_unsigned<T>{}のbool値は「Tがunsigned型である」です。 is_container<T>{}も同様に「Tがコンテナである」になります。 「要素の型がコンテナである」はis_container<typename T::value_type>{}でいけるだろうと思います。 これらの条件を&&で結合して、enabler方式を参考に「std::enable_if<std::is_unsigned<T>{}, std::nullptr_t>」の「std::is_unsigned<T>{}」の部分を置き換えれば良い筈です。
退会済みユーザー

退会済みユーザー

2020/03/24 00:45

value_typeってそのように使えるのですね。問題なく求めていた処理を実現できました。本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問