3

Я хочу изменить порядок экземпляров шаблонов перегрузки. Мой код является следующим:Как изменить заказ шаблона шаблона?

#include <iostream> 
#include <vector> 

using namespace std; 
template<typename T> 
struct Base 
{ 

}; 
template<typename T> 
struct Derived:Base<T> 
{ 

}; 

//template 1 
template<typename T1> 
void f(Base<T1>& a){ 
    cout<<"in 1\n"; 
} 

//template 2 
template<typename T2> 
void f(T2 b){ 
    cout<<"in 2\n"; 
} 

int main(){ 
    Derived<int> v1; 
    f(v1); 
} 

Завещания компилятора выбрало шаблон 2 по умолчанию, но я хочу, чтобы выбрать шаблон 1.

+2

'F (v1)', не позволяют ей найти шаблон для вас ... правила шаблона при создании экземпляра иногда удивительно, если вы позволите компилятор выводит типы. –

+0

Вы должны использовать диспетчер SFINAE или тегов или указать, какую функцию вызывать на сайте вызова. – Jarod42

+0

Вы должны подробно описать, что вы хотите сделать с 'b' в шаблоне 2 и какие аргументы вы хотите * разрешить. Есть простые решения, которые не включают диспетчеризацию тегов, SFINAE или черты, если все, что вы хотите сделать, это напечатать '" в 2 "'. –

ответ

-1

Обеспечить аргумент, который имеет лучший матч:

int main(){ 
    Derived<int> v1; 
    f(v1); // in 2 
    f((Base<int>&)v1); // in 1 
} 

в этом случае f(v1) будет решать f<Base<int>>(v1)

и f((Base<int>&)v1) в f<int>(v1)

+1

или 'f > (v1)'. – iammilind

+1

обязательно ** нет ** такой же. – SergeyA

1

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

#include <type_traits> 
#include <iostream> 

template<typename T> 
struct Base { }; 
template<typename T> 
struct Derived:Base<T> { }; 

template <class T> 
struct template_argument { using type = void*; }; 

template <template <class > class T, class ARG> 
struct template_argument<T<ARG> > { 
    using type = ARG; 
}; 

template <class T> 
using template_argument_t = typename template_argument<T>::type; 

template<typename T1> 
void f(Base<T1>&){ 
    std::cout << "Base-expecting f called\n"; 
} 

template<class T> 
void f(T, std::enable_if_t<!std::is_base_of<Base<template_argument_t<T> >, T>::value>* = nullptr) { 
    std::cout << "Generic f was called.\n"; 
} 

template <class T> 
struct Z { }; 

int main(){ 
    Derived<int> v1; 

    f(v1); 
    f(int()); 
    f(Z<int>()); 
} 

Выход:

Base ожидая F называется

Generic е называется.

Был назван общий f.

+0

@ Jarod42, обратите внимание на эту версию? Я считаю, что он работает так, как ожидалось. – SergeyA

+0

Не знаю, что ожидает OP для 'struct OtherDerived: Base {};'. – Jarod42

+0

@ Jarod42, я тоже не уверен, но я подозреваю, что они хотели бы первую перегрузку? – SergeyA

1

С обычаем черты

template <typename T> std::true_type derive_from_base_impl(const Base<T>*); 
std::false_type derive_from_base_impl(...); 

template <typename T> 
using derive_from_base = decltype(derive_from_base_impl(std::declval<T*>())); 

static_assert(!derive_from_base<int>::value, ""); 
static_assert(derive_from_base<Derived<int>>::value, ""); 

И SFINAE, вы можете сделать

template<typename T> 
void f(Base<T>& a) { std::cout << "in 1\n"; } 

template<typename T> 
std::enable_if_t<!derive_from_base<T>::value> 
f(T b) { std::cout << "in 2\n"; } 

Demo

+0

@SergeyA: с пользовательскими чертами. – Jarod42

+0

Я собрал еще одну версию, которая немного более общая - она ​​не проверяет конкретные базы и производные. Позаботьтесь, чтобы взглянуть? – SergeyA

0

Ответ довольно прост, все, что вам нужно сделать, это предотвратить второй шаблон для создания определенного класса, который можно сделать быстро, используя std::enable_if_t из заголовка type_traits:

Template 2 становится этим, и шаблон 1 остается неизменным

//template 2 
template<typename T2, std::enable_if_t<!std::is_base_of<Base<T2>, T2>::value>> 
void f(T2 b) { 
    cout << "in 2\n"; 
} 
+0

Это немного сложнее, чем это: 'Derived ' наследует от 'Base ', а не 'Base >'. – Jarod42

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