`decltype`并将ADL查找与非ADL查找混合

时间:2013-11-02 16:51:08

标签: c++ c++11 decltype argument-dependent-lookup

测试用例

auto foo(T f)是内部数据类型的情况下,让函数sin(f)的返回类型与从标头cmath调用f时的返回类型相同:

template <typename T>
auto foo(T f) -> decltype(sin(f))
{
    using std::sin;
    return sin(f);
}

这已经破了。 sin(f)内的decltype未在std内查找,因此只找到C变体sin(double),其返回类型为double。以下程序演示了:

#include <cmath>
#include <iostream>
#include <typeinfo>

namespace meh {
    struct Nanometer {};
    struct SinfulNanometer {};
    SinfulNanometer sin(Nanometer) { return SinfulNanometer(); }
}

template <typename T>
auto foo(T f) -> decltype(sin(f))
{
    using std::sin;
    std::cout << typeid(decltype(sin(f))).name() << '\n';
}


int main () {
    std::cout << typeid(decltype(foo(0.))).name() << '\n'
              << typeid(decltype(foo(0.f))).name() << '\n'
              << typeid(decltype(foo(meh::Nanometer()))).name() << '\n';

    foo(0.);
    foo(0.f);
    foo(meh::Nanometer());
}

输出:

d
d
N3meh15SinfulNanometerE
d
f
N3meh15SinfulNanometerE

输出表明double foo->float的返回类型始终为foo->double, {{1}内只有 },由于foo()导致了所有重载,因此找到了正确的sin(float|double)

我想知道这种情况是否已经考虑过了,但这不是我的问题。

问题

我的问题是:

using std::sin具有与名称在foo或ADL-looking-up中的函数相同的返回类型的合理方法是什么?

非工作解决方法:

namespace std

标准提案?

template <typename T>
auto foo(T f) -> decltype(std::sin(f)); // Will miss sin(Nanometer)

使用template <typename T> auto foo(T f) -> decltype(using std::sin; sin(f)); 的排列阻碍了代码自我记录。 enable_if是一个很好的元编程练习。但是为了快速掌握一个看似简单的功能,我认为这不是正确的,因此不符合可维护性的精神。


编辑:我也使用enable_if使用SFINAE不那么模糊,因此带有新decltype声明的C ++ 14可能没有帮助。

2 个答案:

答案 0 :(得分:9)

您可以使用详细命名空间和一些包装:

namespace detail {
    using std::sin;

    template<typename T>
    auto foo(T f) -> decltype(sin(f)) { return sin(f); }
}

template<typename T>
auto foo(T f) -> decltype(detail::foo(f)) { return detail::foo(f); }

答案 1 :(得分:7)

您需要一个级别的间接:

namespace find_sin
{
    using std::sin;
    template<typename T>
    using type = decltype(sin(std::declval<T>()));
}

template <typename T>
find_sin::type<T> foo(T f)
{
    // ...
}