2017-01-13 16 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

Вы можете ввести структуру depedent_type, которая предотвращает template argument deduction.

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) { /*...*/ } 
} 

Что в вашем примере: (. Такое поведение объясняется на cppreference >template argument deduction >non-deduced contexts)

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


Если вы хотите сделать a.foo(1.0) A C ошибка ompilation, вам нужно ограничить первую перегрузку:

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

Этот метод делает выше перегрузки foo принимать только int аргументы: неявные преобразования (например, float до int) не допускаются. Если это не то, что вы хотите, рассмотрите ответ TemplateRex.

wandbox example

(С выше ограниченной функцией, есть любопытное взаимодействие между двумя перегрузками, когда a.foo<int>(1) называется. Я asked a question about it, как я не уверен, лежащими в основе правил, которые определяют его.)

+0

может быть намного проще, с 'foo (double) = delete', нет необходимости в enable_if и не выводимой оболочке, см. Мой anwer :) – TemplateRex

+0

Кажется, это лучший вариант для меня. Другой способ предотвратить «a.foo (1.0)» с меньшими требованиями к компилятору - это сделать что-то вроде «static_assert» (std :: is_same , «...»); '. – cyberguijarro

1

безусловно, самый простой способ сделать то, что вы хотите явно удалить перегрузку вы не хотите:

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  
} 

С последней строкой в ​​основном закомментированный 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; 
+0

Обратите внимание, что этот подход позволяет вызывать 'foo' с' float', 'char' * (и все типы неявно конвертируются в' int') *. Не уверен, что это то, чего хочет OP. –

+0

@VittorioRomeo уверен, но то же самое относится и к вашему решению: нужен ли он именно 'int', или только неплавающие или только не суживающиеся преобразования и т. Д. В любом случае решение' = delete' может быть расширено до исключить (но не удалить, потому что вы хотите получить ошибку) другие перегрузки. – TemplateRex

+0

Да, я не критикую ваш ответ - просто говорю, что вы, вероятно, должны это упомянуть. Я обновлю свой ответ, чтобы было ясно, что неявные преобразования не принимаются. –

0

Добавление другого предложения в банк, и в том же духе, как ответ Витторио вы можете также добавить еще один параметр шаблона для подписи:

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

Затем, чтобы использовать его необходимо указать первый параметр шаблона, поскольку он не может быть выводится. Это имеет небольшое преимущество в том, чтобы различать то, что хотел пользователь, и то, что было передано, что может быть полезно в некоторых случаях.

 Смежные вопросы

  • Нет связанных вопросов^_^