【问题标题】:Function template overload resolution函数模板重载解析
【发布时间】:2014-05-19 19:20:33
【问题描述】:

我想编写一些模板函数来以定义的方式处理类型双关语,所以我想出了这两个函数。第一个获取一个对象并通过双关语将其转换为另一个对象。它确保两种类型都是 POD 并且大小相同。第二个旨在简单地获取任何指针(就像 void*),但仍然检查以确保指针指向 POD 类型。我遇到的问题是,如果我传递一个非常量指针,那么将使用第一个函数。处理此问题的最佳方法是什么?

template <class TO, class FROM>
FORCE_INLINE TO punning_cast(const FROM &input)
{
    static_assert(std::is_pod<TO>::value, "TO must be POD");
    static_assert(std::is_pod<FROM>::value, "FROM must be POD");
    static_assert(sizeof(TO) == sizeof(FROM), "TO and FROM must be the same size");

    TO out;
    std::memcpy(&out, &input, sizeof(TO));
    return out;
}

template <class TO, class FROM>
FORCE_INLINE TO punning_cast(const FROM *input)
{
    static_assert(std::is_pod<TO>::value, "TO must be POD");
    static_assert(std::is_pod<FROM>::value, "FROM must be POD");

    TO out;
    std::memcpy(&out, input, sizeof(TO));
    return out;
}

【问题讨论】:

  • 也许typename std::enable_if&lt;!std::is_pointer&lt;FROM&gt;::value,TO&gt;::type 作为前者的返回类型可能会有所帮助(我不会尝试任何,请注意)。
  • @WhozCraig 我已经回答过了
  • (只是指出这一点,以免看起来我偷了你的评论来回答)

标签: c++ templates c++11 type-conversion type-punning


【解决方案1】:

函数模板mix weirdly with overloading.

一种可能的解决方案(不是唯一的)是使用enable_if 来声明每个函数,从而为指针类型启用第二个,反之亦然

#include <type_traits>

template <class TO, class FROM>
FORCE_INLINE typename enable_if<!is_pointer<FROM>::value, TO>::type
    punning_cast(const FROM &input) { ... }

template <class TO, class FROM>
FORCE_INLINE typename enable_if<is_pointer<FROM>::value, TO>::type
    punning_cast(const FROM input) { ... }

因此,实现消歧(在引用和指针之间)的示例是this one

【讨论】:

  • 我不确定“功能模板不会超载”是否完全准确,但其余部分 +1。
  • @MooingDuck 过于简单化了?我本来打算进入function template overload resolution,但后来我不得不超出问题的范围(你认为我应该删除它以防止误解?)
  • 我想我只需将其更改为“函数模板与重载混合在一起很奇怪,请参阅link。”
  • @MooingDuck 好主意,会这样做。 Thnx(语言律师可能会大喊“函数模板的实例是参与重载过程的实例”,但这种措辞也避免了这种情况;)
  • 这看起来很有趣,但是我在使用它时遇到了另一个问题。如果我传递一个数组,我会收到一个关于不明确重载的错误。
【解决方案2】:

免责声明:我更喜欢 C++11 及更高版本的 Nikos Athanasiou's answer

解决这个(常见)问题的一种方法是将函数包装在结构中并添加一个辅助函数来选择其中一个:

template <class TO, class FROM>
struct punning_cast_impl
{
    static FORCE_INLINE TO cast(const FROM &input)
    {
        static_assert(std::is_pod<TO>::value, "TO must be POD");
        static_assert(std::is_pod<FROM>::value, "FROM must be POD");
        static_assert(sizeof(TO) == sizeof(FROM), "TO and FROM must be the same size");

        TO out;
        std::memcpy(&out, &input, sizeof(TO));
        return out;
    }
};

template <class TO, class FROM>
struct punning_cast_impl<TO, FROM*>
{
    static FORCE_INLINE TO cast(const FROM *input)
    {
        static_assert(std::is_pod<TO>::value, "TO must be POD");
        static_assert(std::is_pod<FROM>::value, "FROM must be POD");

        TO out;
        std::memcpy(&out, input, sizeof(TO));
        return out;
    }
};

template<class TO, class FROM>
TO FORCE_INLINE punning_cast(const FROM& input)
{
    return punning_cast_impl<TO, FROM>::cast(input);
}

int main()
{
    double d1 = 50.0;
    int64_t i1 = punning_cast<int64_t>(d1); // calls version #1

    double d2 = 100.0;
    int64_t i2 = punning_cast<int64_t>(&d2); // calls version #2
}

【讨论】:

  • +1 你打败了我。我会为punninc_cast_impl::cast 函数的正式参数添加一个const。否则将不能用于指向const 的指针的实际参数。
  • @Cheersandhth.-Alf 哎呀;在复制中不知何故丢失了。谢谢。
  • +1 出于体育精神。虽然更长,但这个答案可以很好地扩展,只能根据手头的问题做出选择。做得很好。
猜你喜欢
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多