2017-01-13 3 views
6

防止暗黙のテンプレートインスタンス

struct A 
{ 
    void foo(int i) { /*...*/ } 
    template<typename T> void foo(T t) { /*...*/ } 
} 

明示的に命令されない限り、どのように私は、テンプレートのインスタンス化を防ぐことができます?:

A a; 
a.foo<int>(1); // ok 
a.foo<double>(1.0); // ok 
a.foo(1); // calls non-templated method 
a.foo(1.0); // error 

感謝を!

+3

これが必要ですか?関数をオーバーロードするのではなく、 'int'のテンプレートを特殊化するのはなぜでしょうか? –

+0

@ChristianHacklは 'foo(double)= delete'を実行します。私の答えを見てください。 – TemplateRex

答えて

9

template argument deductionを防止するdepedent_type構造体を導入することができます。

あなたの例では
template <typename T> 
struct dependent_type 
{ 
    using type = T; 
}; 

struct A 
{ 
    void foo(int i) { /*...*/ }; 
    template<typename T> void foo(typename dependent_type<T>::type t) { /*...*/ } 
} 

:あなたはa.foo(1.0) Cを作りたい場合は

a.foo<int>(1);  // calls the template 
a.foo<double>(1.0); // calls the template 
a.foo(1);   // calls non-templated method 
a.foo(1.0);   // calls non-templated method (implicit conversion) 

wandbox example

(この動作はcppreference >template argument deduction >non-deduced contextsに説明されている。)


ompilationエラーは、最初に過負荷を制限する必要があります。

template <typename T> 
auto foo(T) -> std::enable_if_t<std::is_same<T, int>{}> { } 

この技術はfooの上記過負荷のみint引数取ります:暗黙的な変換(例えばをfloatintは許可されません。これがあなたが望むものでないなら、TemplateRexの答えを考えてください。

wandbox example

(上記の制約機能により、a.foo<int>(1)が呼ばれた2つのオーバーロードの間で好奇心旺盛な相互作用がある。私asked a question about it私はそれを導く基礎となるルールのわからないと。)

断然
+0

は 'foo(double)= delete'を使ってずっと簡単にできます。enable_ifと非推測ラッパーは必要ありません。私のアンカーを見てください。 – TemplateRex

+0

これは私にとって最良の選択肢のようです。 'a.foo(1.0)'がコンパイラの準拠要件を満たさないようにするもう一つの方法は 'static_assert(std :: is_same 、" ... ");'のようなことです。 – cyberguijarro

1

あなたが欲しいものを行うための最も簡単な方法は、明示的にあなたがしたくない過負荷を削除することです:

void foo(double) = delete; 

すなわちthis prints

void A::foo(T) [with T = int] 
void A::foo(T) [with T = double] 
void A::foo(int) 

this prints

prog.cc: In function 'int main()': 
prog.cc:18:16: error: use of deleted function 'void A::foo(double)' 
    a.foo(1.0);   // error 
       ^
prog.cc:6:10: note: declared here 
    void foo(double) = delete; 
に残された最後の行をコメントアウトメインの最後の行で

#include <iostream> 

struct A 
{ 
    void foo(int) { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    void foo(double) = delete; 

    template<typename T> 
    void foo(T) {std::cout << __PRETTY_FUNCTION__ << "\n"; } 
}; 

int main() 
{  
    A a; 
    a.foo<int>(1);  // ok 
    a.foo<double>(1.0); // ok 
    a.foo(1);    // calls non-templated method 
    a.foo(1.0);   // error  
} 

次の明示的な例を持っています

+0

このアプローチでは 'float'、' char' *(暗黙のうちに 'int'に変換可能なすべての型)*で' foo'を呼び出すことができます。これがOPが望んでいるものかどうかはわかりません。 –

+0

@VittorioRomeo確かに、同じことがあなたのソリューションにも当てはまります:彼はちょうど 'int'を必要とするのか、あるいは非浮動小数点の変換か非狭めの変換のみを望んでいますか?どんな場合でも、' = delete'ソリューションは他のオーバーロードを除外します(ただし、エラーが発生するため削除しません)。 – TemplateRex

+0

はい、私はあなたの答えを批判しているわけではありません。暗黙の変換が受け入れられないことを明確にするために、私の答えを更新します。 –

0

ポットに別の提案を追加し、ヴィットリオの回答と同様の調子であなたも署名に別のテンプレートパラメータを追加することができます。

template <class UserType, class InputType> 
void foo(InputType x){...} 

そして、それを使用することができないため、あなたが最初のテンプレートパラメータを指定する必要があります推測される。これには、ユーザが望んでいたものと受け入れられたものを区別することができるというわずかな利点があります。

関連する問題