如何更改模板实例化顺序?

时间:2016-04-15 14:37:28

标签: c++ templates inheritance instantiation generic-programming

我想更改重载模板的实例化顺序。我的代码如下:

#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。

4 个答案:

答案 0 :(得分: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>() );
}

输出:

  

基础期待f叫

     

通用f被称为。

     

通用f被称为。

答案 1 :(得分:1)

With custom traits

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, "");

And SFINAE, you may do

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

答案 2 :(得分:0)

答案很简单,你所要做的就是阻止第二个模板为某个类实例化,这可以使用type_traits标题中的std::enable_if_t快速完成:

模板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";
}

答案 3 :(得分:-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)