函数指针的类型特征?

问题描述 投票:0回答:1

我需要有条件地使用 std::absstd::fabs 内的模板类,这里是相关代码的简化版。

template <typename T>
class C
{
public:
    using type = std::conditional_t<std::is_integral_v<T>, std::uint64_t, long double>;
    using check = std::is_integral<type>;

    // ERROR: mismatch in format parameter list
    constexpr auto ptr_abs = check::value ? &std::abs<check::value_type> : &std::fabs;

    // use pointer
    void use_ptr()
    {
        auto x = (*ptr_abs)(-3);
    }
};

对我来说,所有的尝试都没有用,我毫无头绪。

int main()
{
     C<int> a;
     a.f();

     C<float> b;
     b.f();
}
c++ typetraits
1个回答
2
投票

你真的需要使用函数指针吗?利用C++的类型安全机制不是更好吗?比如如下。

template <typename T>
class C
{
public:
    using type = std::conditional_t<std::is_integral_v<T>, std::uint64_t, long double>;
    static const bool check = std::is_integral_v<type>;

    std::function<type(type)> abs = [](auto arg)
    {
        if constexpr (check) return std::abs(static_cast<long long>(arg));
        else return std::fabs(arg);
    };

    void use()
    {
        auto x = abs(-3);
    }
};

This 行之有效. 只是要注意,没有 std::abs 的无符号整数,因此,为了避免歧义,我必须选择一个特定的重载,通过投射(到 long long 在这个例子中,我不知道什么是 Result).


在C++17之前,这里没有 if constexpr你可以通过使用模板特殊化来实现同样的目标,只是多了一些类型。


1
投票

用指针的类型来解决函数重载的问题。

#include <cmath>
#include <type_traits>
#include <cstdlib>
#include <iostream>

template <typename T>
class C {
public:
    static constexpr T (*ptr_abs)(T) = &std::abs;
    void f() {
        std::cout << typeid(ptr_abs).name() << "\n";
        auto x = (*ptr_abs)(-3);
    }
};

int main()
{
     C<int> a;
     a.f(); // PFiiE
     C<float> b;
     b.f(); // PFffE
     C<double> c;
     c.f(); // PFddE
}

1
投票

也许我误解了你的问题 但在我看来,你可以单独定义你的版本的 abs 然后在其他类中使用它。

#include <cmath>
#include <cstdint>
#include <complex>
#include <iostream>
#include <limits>
#include <type_traits>
#include <typeinfo>

namespace my {

template <class T>
auto abs_(T x)
{
    if constexpr ( std::is_unsigned_v<T> ) {
        return static_cast<uintmax_t>(x);
    }
    else if constexpr ( std::is_integral_v<T> ) {
        return static_cast<uintmax_t>(std::abs(static_cast<intmax_t>(x)));
    }
    else {
        return std::fabs(static_cast<long double>(x));
    }  
}

template <class T>
auto abs_(std::complex<T> const& x)
{
    return std::abs(static_cast<std::complex<long double>>(x));
}

}

template <typename T>
class C
{
public:
    void use(T x)
    {
        std::cout << typeid(T).name() << ' ' << x;
        auto a = my::abs_(x);
        std::cout << ' ' << typeid(a).name() << ' ' << a << '\n';
    }
};

int main()
{
    C<int> a;
    a.use(-42);

    C<float> b;
    b.use(-0.1);

    C<long long> c;
    c.use(std::numeric_limits<long long>::min());

    C<size_t> d;
    d.use(-1);

    C<std::complex<double>> e;
    e.use({-1, 1});
}

可测试 此处.

© www.soinside.com 2019 - 2024. All rights reserved.