2011-09-30 39 views
6

我有一個問題,我想提供一個函數foo的通用版本,它只能在絕對沒有其他匹配調用時應用。如何修改以下代碼,使last_resort::fooderived::typebase::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::foo可以從與disable_if設置過載被移除。如果foo(T)是其他格式良好的話,這個想法是禁用last_resort::foo(T)。這會導致last_resort::foo(T)成爲foo最壞匹配:

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

} 

輸出:

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

This answer描述如何構建用於檢查返回void一個函數(foo)的存在的溶液中。

1

你不能做太多的事情。這兩個foo函數都在重載集合中。但你的last_resort之一是一個更好的匹配,因爲它不需要像base :: foo for derived :: type()那樣進行轉換。只有在兩個候選人通過參數和可能的轉換來判斷「同樣好」的情況下,非模板纔是優選的。

+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我移動用戶定義的轉換到僞參數:

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,因爲你得到了所有奇怪的類型。但是保存它很困難。模板參數扣減不會生成這些用戶定義的轉換。 – MSalters

+0

古代的帖子,但隨機的想法:如何使用原始的'badParam',但使'badParam'模板類型與模板參數值指針實際調用的函數,它在它的構造函數中這樣做。 – Yakk