2011-09-30 6 views
6

私は、機能の汎用バージョンfooを提供したいと思っています。これは、呼び出しに他の一致が全くない場合にのみ適用できます。 last_resort::fooderived::typeの場合、base::fooより悪い一致となるように、次のコードを変更するにはどうすればよいですか?私はbarの定義を変更することを伴わず、last_resort::fooの引数の型を保持する解決策を見出したいと思います。ADL中に関数テンプレートの優先度を下げる方法は?

#include <iostream> 

namespace last_resort 
{ 

template<typename T> void foo(T) 
{ 
    std::cout << "last_resort::foo" << std::endl; 
} 

} 

template<typename T> void bar(T) 
{ 
    using last_resort::foo; 
    foo(T()); 
} 

namespace unrelated 
{ 

struct type {}; 

} 

namespace base 
{ 

struct type {}; 

void foo(type) 
{ 
    std::cout << "base::foo" << std::endl; 
} 

} 

namespace derived 
{ 

struct type : base::type {}; 

} 

int main() 
{ 
    bar(unrelated::type()); // calls last_resort::foo 
    bar(base::type());  // calls base::foo 
    bar(derived::type()); // should call base::foo, but calls last_resort::foo instead 

    return 0; 
} 

答えて

0

last_resort::foodisable_ifで設定過負荷から除去することができます。考え方は、を無効にし、それ以外の場合はfoo(T)が整形式であることです。

namespace test 
{ 

template<typename T> struct has_foo { ... }; 

} 

namespace last_resort 
{ 

template<typename T> 
    struct disable_if_has_foo 
    : std::enable_if< 
     !test::has_foo<T>::value 
     > 
{}; 

template<typename T> 
    typename disable_if_has_foo<T>::type foo(T) 
{ 
    std::cout << "last_resort::foo" << std::endl; 
} 

} 

出力:これはfooのための最悪の試合であることをlast_resort::foo(T)を引き起こし

$ g++ last_resort.cpp 
$ ./a.out 
last_resort::foo 
base::foo 
base::foo 

This answervoidを返す関数(foo)の存在をチェックするためのソリューションを構築する方法について説明します。

1

あなたはそれについて多くを行うことはできません。両方のfoo関数がオーバーロードセットに含まれています。しかし、last_resort型は、derived :: type()のためにbase :: fooと違って変換を必要としないため、より良いマッチです。 2つの候補がパラメータおよび可能な変換によって判断される「同等に良好」である場合にのみ、非テンプレートが好ましい。

+0

これは本当ですが、fooに「隠し」変換を導入する方法があるのでしょうか? –

+0

私はそれが動作するとは思わない。あなたが得ることができる「最良の」と言うことから、コンパイルが失敗するようなあいまいさがあります。しかし、多分、私は何かが欠けている。 – sellibitze

+0

解決策は、 '' 'last_resort :: foo'''の戻り値の型を、' '' disable_if_foo_exists :: type''のようなもので飾ることです。これはSFINAEを使ってフリーの '' foo ''関数。もし存在すれば、 '' last_resort :: foo'''はオーバーロードセットから削除されます。 –

0

derived::typeの宣言の後に、derived::typeの場合、barのオーバーロードを指定できます。これはnamespace derivedにあるかもしれません。

void bar(derived::type) 
{ 
    foo(derived::type()); 
} 
2

これは、それを取得ほど悪くについて次のようになります。

struct badParam { template <typename T> badParam(T t) { } }; 
namespace last_resort { 
    void foo(badParam, int dummy = 0, ...) { 
    std::cout << "last_resort::foo" << std::endl; 
    } 
} 

あなたは、ユーザー定義の変換、不履行パラメータおよび未使用の省略記号を持っています。

[編集]

わずかバリアント、Tを保存するIダミーパラメータにユーザ定義の変換移動:

struct badParam { 
    badParam() { } 
    operator int() { return 42; } 
}; 
namespace last_resort { 
    template <typename T> void foo(T t, int dummy = badParam(), ...) { 
    std::cout << "last_resort::foo" << std::endl; 
    } 
} 
+0

ありがとうございます。私は '' badParam''だけを追加するだけで降格することができますが、変換の中で '' T''の型を消去すると思います。 –

+0

まあ、最後のリゾートの場合、あなたはすべての奇妙なタイプを得るので、とにかくTに頼ることはできません。しかし、それを保存するのは難しいです。 Template Argument Deductionはそれらのユーザ定義の変換を生成しません。 – MSalters

+0

古代のポストだがランダムな考え方:元の 'badParam'を使うのはどうでしょう?' badParam'をテンプレート引数の値を持つテンプレート型にして、呼び出す実際の関数へのポインタをコンストラクタで行います。 – Yakk