首先强制执行一次重载,然后再回到另一次重载之前

时间:2015-01-31 08:38:55

标签: c++ templates sfinae

作为更广泛问题的一个例子,给定这两个重载,你可能会认为数组版本在传递数组时会优先:

template <size_t N>
void bar(const char (&)[N]) { 
    std::cout << "array, size=" << N-1 << std::endl;
}
void bar(const char *s)  { 
    std::cout << "raw, size=" << strlen(s) << std::endl;
}

但是当传递数组(字符串文字是数组)bar("hello")时,将调用后一版本(指针版本)。

关于SO的这个特殊情况has been discussed,答案很有趣。但这里有一个普遍的问题。我想强制编译器更喜欢一个重载,并且只在所有合法的调用尝试失败时才放弃该重载。

为了清楚起见,我们将其重命名为bar1bar2

template <size_t N>
void bar1(const char (&)[N]) { 
    std::cout << "array, size=" << N-1 << std::endl;
}
void bar2(const char *s)  { 
    std::cout << "raw, size=" << strlen(s) << std::endl;
}

如果不进一步改变,我们可以写下这样的东西:

template<typename ...Args>
auto try_bar1_then_bar2(Args&& ...args) -> ??? { 
    ... will first attempt to perfect forward to bar1 ...
    ... only if bar1 cannot be called, fallback to bar2 ...
}

我在这个问题中使用了一些C ++ 11,并且&amp;&amp;为了完美转发,但我想一般问题也适用于早期的C ++。是否有一种简单,通用的方法来强制重新排序过载优先级?当一组函数(具有不同的名称?)(几乎不可调用)时,如何准确控制它们的尝试顺序?

2 个答案:

答案 0 :(得分:2)

一些表达SFINAE:

template<typename ...Args>
auto try_bar1_then_bar2_IMPL(int, Args&& ...args) -> decltype( bar1(forward<Args>(args)...) ) { 
    cout << "Yes, we can call bar1" << endl;
    return bar1(forward<Args>(args)...);
}
template<typename ...Args>
auto try_bar1_then_bar2_IMPL(char, Args&& ...args) -> void { 
    cout << "No, can't call bar1, calling bar2 instead." << endl;
    return bar2(forward<Args>(args)...);
}
template<typename ...Args>
auto try_bar1_then_bar2(Args&& ...args) -> decltype( try_bar1_then_bar2_IMPL(0, forward<Args>(args)...) ) { 
    return try_bar1_then_bar2_IMPL(0, forward<Args>(args)...);
}

如果无法调用bar1,则try_bar1_then_bar2_IMPL的第一次重载无效,因为返回类型中的decltype失败。但是如果可以调用bar1,那么两者都是有效的(并且我认为完全匹配)。因此,我在前面添加了一个虚拟参数,intchar,这打破了有利于bar1的调用。

这就是这样称呼的:

try_bar1_then_bar2("hello");  // array, calls array version
try_bar1_then_bar2(+"hello"); // + converts to a pointer, therefore
                                 // this calls the pointer ('raw') version.

答案 1 :(得分:0)

您可以使用模板包装参数以获取所需的重载函数:

#include <cstring>
#include <iostream>

template <typename T>
struct Wrap
{
    const T& value;

    Wrap(const T& value)
    : value(value)
    {}
};

template <typename T>
inline Wrap<T> wrap(const T& value) {
    return Wrap<T>(value);
}


template <size_t N>
void bar(const Wrap<char[N]>&) {
    std::cout << "array, size=" << N-1 << std::endl;
}

void bar(const Wrap<const char *>& s)  {
    std::cout << "raw, size=" << strlen(s.value) << std::endl;
}

template <typename T>
void bar(const T& value) {
    bar(wrap(value));
}


int main(int argc, char* argv[]) {
    const char a[] ="hello";
    const char* s ="hello";
    bar(a);
    bar(s);
}