2011-09-30 36 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