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

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

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

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

コンパイルエラー

コンパイルのフェーズで生成されるエラーです。よく無効なシンタックスやタイプが含まれているとき発生します。

C++

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

Q&A

解決済

3回答

6949閲覧

関数テンプレートの完全特殊化のコンパイルエラー

JADEN

総合スコア106

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

コンパイルエラー

コンパイルのフェーズで生成されるエラーです。よく無効なシンタックスやタイプが含まれているとき発生します。

C++

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

0グッド

2クリップ

投稿2016/02/10 15:19

コンパイルエラーになる原因を教えてください。
コンパイラー: VC++ 2015

C++

1// main.cpp 2#include "sub.h" 3#include <iostream> 4#include <string> 5 6int main() { 7 std::string string0("test"); 8 std::cout << GetLength(string0) << std::endl; 9 10 const char* string1 = "test"; 11 std::cout << GetLength(string1) << std::endl; 12}

C++

1// sub.h 2#ifndef SUB_H 3#define SUB_H 4 5#include <string> 6 7template <typename type> 8std::size_t GetLength(const type& string) { 9 return string.length(); 10} 11 12template <> 13std::size_t GetLength<char*>(const char*& string) { 14 return std::strlen(string); 15} 16 17#endif
エラーメッセージ エラー (アクティブ) 指定された型と一致する 関数テンプレート "GetLength" のインスタンスはありません エラー C2912 明示的な特殊化 'size_t GetLength<char*>(const char *&)' は関数テンプレートの特殊化ではありません エラー C2912 明示的な特殊化 'size_t GetLength<char*>(const char *&)' は関数テンプレートの特殊化ではありません

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

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

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

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

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

guest

回答3

0

C++

1template <typename type> 2std::size_t GetLength(const type& string) { 3 return string.length(); 4} 5```このコードの`const type& string`の`const`は`type&`を修飾しています。 6 7```C++ 8template <> 9std::size_t GetLength<char*>(const char*& string) { 10 return std::strlen(string); 11} 12```こちらのコードの`const char*& string`の`const`は`char*`を修飾しています。つまり、`type`に相当する部分が`const char*`となり、`<char*>`とも`const type&`とも一致しないため、テンプレートの特殊化ではないというエラーになるのです。 13 14コンパイルを通すためには`char* const& string`のように書く必要があります。 15 16ただし、その場合、`const char*`を引数で渡すと上の関数テンプレートと一致してしまい、別のエラーになります。そのため、`const char* const& string`という特殊化も用意する必要があり、冗長なコードになってしまいます。 17 18C++11からは、もうちょっとスマートに書けるようになっています。 19```C++ 20template <typename type, class = typename std::enable_if<std::is_class<type>::value>::type> 21std::size_t GetLength(const type& string) { 22 return string.length(); 23} 24 25std::size_t GetLength(const char* string) { 26 return std::strlen(string); 27} 28```テンプレート引数が長くなっていますが、`type`がクラスの時だけ一致させる仕組みです。 29 30下はテンプレートの特殊化ではなく通常の関数のオーバーロードにしています。テンプレートの特殊化だとコードが冗長になることがあるので、通常のオーバーロードで書くことが多いです。

投稿2016/02/10 16:44

catsforepaw

総合スコア5938

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

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

JADEN

2016/02/11 12:50 編集

回答ありがとうございます。 そもそも、完全特殊化の実装をsub.hに書いており、アップしたコードには書いてないですが、main.cpp以外のソースファイルからもsub.hをインクルードしていたため、二重定義になっていたようです。 普通の関数・クラステンプレートは、ヘッダファイルに実装を書くため、同じ書き方だと思い込んでいました。
JADEN

2016/02/11 12:55 編集

>>下はテンプレートの特殊化ではなく通常の関数のオーバーロードにしています。テンプレートの特殊化だとコードが冗長になることがあるので、通常のオーバーロードで書くことが多いです。 コードが冗長になることを除き、完全特殊化とオーバーロードの違いがない様に思えるのですが、何か違いがあるのでしょうか。
catsforepaw

2016/02/11 13:38

> 何か違いがあるのでしょうか。 同じです。同じ結果になるなら見やすい方がいいという理屈です。 ただ、コンパイラが呼ぶべき関数を特定する際、先にオーバーロードの関数から一致する型があるかどうか探して、なければテンプレートの特殊化を探し、それでもなければテンプレートに当てはめる、ということをやっているので、優先順という違いはあります。
guest

0

ベストアンサー

こんにちは。

一見不思議に見えますが、実はconstのかかり具合が一致してません。
const type&と書くとconsttypeにかかります。近い方にかかります。
const char*&と書くとconstchar*ではなくcharにかかります。近い方にかかるからです。
const type&typechar*に置き換えると、コンパイラ的にはconst (char*)&(*1)となってますが、ソースの記述は(const char)* &になっていて矛盾しているため、特殊化として認識されません。
(*1)実際に書くとエラーになります。

そこで、yohhoyさんが書かれているようにすれば通ります。
constは左、右どちらにおいてもよいので下記のように考えると分かりやすいと思います。
(個人的にはconstは右においた方が間違いを減らせると考えてます。)

C++

1template <typename type> 2std::size_t GetLength(type const& str) { 3 return str.length(); 4} 5 6template <> 7std::size_t GetLength<const char*>(const char* const& str) { 8 return std::strlen(str); 9}

でも、このケースであれば、関数テンプレートをやめて暗黙の型変換を利用して下記のように書いても動作します。

C++

1std::size_t GetLength(const std::string& str) { 2 return str.length(); 3}

std::string型はchar const*を受け取れるので、string1は暗黙の型変換でstd::string型の一時オブジェクトへ変換されます。そして、const参照は一時オブジェクトを受け取れます。


ところで、型名と判別し辛い変数名は使わないことを強くお薦めします。
机上デバッグが辛いですから。

投稿2016/02/10 16:40

Chironian

総合スコア23272

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

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

JADEN

2016/02/11 12:59

回答ありがとうございます。 >> ところで、型名と判別し辛い変数名は使わないことを強くお薦めします。 型は英語でtypeなので、typeとしました。 他に良い名前があれば教えてください。
Chironian

2016/02/11 13:12

各GetLength()引数名のstringの件です。std::stringと紛らわしいと思います。
guest

0

下記なら通るでしょうか?

C++

1template <> 2std::size_t GetLength<const char*>(const char* const& string) { 3 return std::strlen(string); 4}

投稿2016/02/10 16:14

yohhoy

総合スコア6191

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

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

catsforepaw

2016/02/10 16:50

私の回答の方でも触れていますが、それだと`char *`を受け付けてくれません。ですからconstなし版も書かないとエラーになってしまいます。
yohhoy

2016/02/10 22:54

そうですね。この例では無理に特殊化するのではなく、関数オーバーロードの方が適切かと思います。
JADEN

2016/02/11 13:00

回答ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問