3

オーバーロードテンプレートのインスタンス化順序を変更したいと思います。私のコードは次のとおりである:コンパイラはデフォルトとしてテンプレート2を選んだのだろうテンプレートインスタンス化の順序を変更するにはどうすればよいですか?

#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); 
} 

、私はそれがテンプレート1

+2

'F (V1)'のまま、あなたが許可すれば、テンプレートのインスタンス化のルールは、時には驚くべきことである...それはあなたのためのテンプレートを見つけることはできません。コンパイラは型を推論します。 –

+0

SFINAEまたはタグディスパッチを使用するか、コールサイトで呼び出す関数を指定する必要があります。 – Jarod42

+0

あなたはテンプレート2の 'b'で何をしたいのか、あなたが*望む*の引数について詳しく述べるべきです。あなたがしたいことが2 "で印刷するだけであれば、タグディスパッチ、SFINAE、または特性を含まない簡単なソリューションがあります。 –

答えて

-1

を選んだしたい、より良い試合を持っているの引数を提供します

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

この場合、 f(v1)f<int>(v1)f<Base<int>>(v1)

f((Base<int>&)v1)に解決されます

+1

または 'f >(v1)'です。 – iammilind

+1

それはもちろん**同じではありません。 – SergeyA

1

これは、過負荷解決の設定であり、2番目の過負荷が選択されているのは、これが適切です。適切な過負荷が選択されているかどうかを確認するコードをまとめると予想されていたよりも挑戦的だったようです。ここでは、次のとおりです。

#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が呼び出されました。カスタムで

+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

もう少し一般的な別のバージョンをまとめました。特定のBaseとDerivedをチェックしません。見てケア? – SergeyA

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"; 
} 
+0

これは少し複雑です。 'Derived 'は 'Base'から継承し、' Base'から継承します。 – Jarod42

関連する問題