5

测试用例

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

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

这已破了。不查找 inside sin(f),因此只找到返回类型为的变体。下面的程序演示了:decltypestdCsin(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

输出表明返回类型始终doublefoo->float and foo->double,仅在 内 ,因为导入所有重载的 ,才找到foo()正确的类型。sin(float|double)using std::sin

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

问题

我的问题是:

什么是让foo具有相同返回类型的函数与名称在namespace std或 ADL-looked-up 的函数相同的明智方法?

非工作解决方法:

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是元编程的一个很好的练习。但是要快速掌握一个看似简单的功能,恕我直言,这不是正确的事情,因此不符合可维护性的精神。


编辑:我也decltype习惯于不那么隐晦地使用 SFINAE,因此带有新auto foo() {....}声明的 C++14 可能无济于事。

4

2 回答 2

10

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

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); }
于 2013-11-02T16:55:07.897 回答
8

您需要一级间接:

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)
{
    // ...
}
于 2013-11-02T16:55:50.997 回答