gpt4 book ai didi

c++ - 使用 std::enable_if<> 的模板特化

转载 作者:太空狗 更新时间:2023-10-29 21:18:08 27 4
gpt4 key购买 nike

编译并运行以下代码:

#include <cinttypes>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <sstream>
#include <stdexcept>

class UnsignedBox {
public:
typedef std::uint64_t box_type;

template<typename UNSIGNED_TYPE,
typename std::enable_if<
std::numeric_limits<UNSIGNED_TYPE>::is_signed==false &&
(sizeof(UNSIGNED_TYPE) >= sizeof(UnsignedBox::box_type)), int>::type = 0
>
UNSIGNED_TYPE toUnsigned()const {
//We've established we're not returning a smaller type so we can just
//return our value.
return value;
}

template<typename UNSIGNED_TYPE,
typename std::enable_if<std::numeric_limits<UNSIGNED_TYPE>::is_signed==false &&
(sizeof(UNSIGNED_TYPE) < sizeof(UnsignedBox::box_type)), int>::type = 0
>
UNSIGNED_TYPE toUnsigned()const {
//We are returning a smaller type so we need a range check.
if(value>static_cast<box_type>(std::numeric_limits<UNSIGNED_TYPE>::max())){
std::ostringstream msg;
msg<<value<<'>'<<
static_cast<box_type>(std::numeric_limits<UNSIGNED_TYPE>::max());
throw std::logic_error(msg.str());
}
return value;
}

UnsignedBox(const box_type ivalue): value(ivalue){}
private:
box_type value;

};

int main(int argc, char*argv[]) {

UnsignedBox box(
static_cast<UnsignedBox::box_type>(
std::numeric_limits<std::uint32_t>::max())+10
);

std::uint64_t v(box.toUnsigned<std::uint64_t>());
std::cout<<v<<std::endl;

try {
std::uint32_t v(box.toUnsigned<std::uint32_t>());
}catch(const std::logic_error err){
std::cout<<err.what()<<std::endl;
}

return EXIT_SUCCESS;
}

预期输出(所有支持平台):

4294967305
4294967305>4294967295

到目前为止一切顺利。

但我真正想做的(为了代码清晰):

声明如下:

template<typename UNSIGNED_TYPE>
UNSIGNED_TYPE toUnsigned()const;

然后提供专门的实现,例如:

template<typename UNSIGNED_TYPE, 
typename std::enable_if<
std::numeric_limits<UNSIGNED_TYPE>::is_signed==false &&
(sizeof(UNSIGNED_TYPE) >= sizeof(UnsignedBox::box_type)), int>::type = 0
>
UNSIGNED_TYPE UnsignedBox::toUnsigned()const {
//We've established we're not returning a smaller type so we can just
//return our value.
return value;
}


template<typename UNSIGNED_TYPE,
typename std::enable_if<std::numeric_limits<UNSIGNED_TYPE>::is_signed==false &&
(sizeof(UNSIGNED_TYPE) < sizeof(UnsignedBox::box_type)), int>::type = 0
>
UNSIGNED_TYPE UnsignedBox::toUnsigned()const {
//We are returning a smaller type so we need a range check.
if(value>static_cast<box_type>(std::numeric_limits<UNSIGNED_TYPE>::max())){
std::ostringstream msg;
msg<<value<<'>'<<
static_cast<box_type>(std::numeric_limits<UNSIGNED_TYPE>::max());
throw std::logic_error(msg.str());
}
return value;
}

但是我得到这个错误:

xxx.cpp:nn:20: error: prototype for 'UNSIGNED_TYPE UnsignedBox::toUnsigned() const' does not match any in class 'UnsignedBox'
UNSIGNED_TYPE UnsignedBox::toUnsigned()const {
^ xxx.cpp:nn:23: error: candidate is: template<class UNSIGNED_TYPE> UNSIGNED_TYPE UnsignedBox::toUnsigned() const
UNSIGNED_TYPE toUnsigned()const;
^

这很奇怪,因为如果你问我

UNSIGNED_TYPE UnsignedBox::toUnsigned() const

非常适合

UNSIGNED_TYPE toUnsigned()const;

我做错了什么?

PS:这不是实际问题,但我的问题是类似的,我想根据编译时检查的基本类型的属性来特殊化一些模板。

最佳答案

你不能用一个签名声明一个函数:

template<typename UNSIGNED_TYPE>
UNSIGNED_TYPE toUnsigned() const;

然后用不同的签名定义它:

template<typename UNSIGNED_TYPE, 
typename std::enable_if<
std::numeric_limits<UNSIGNED_TYPE>::is_signed==false &&
(sizeof(UNSIGNED_TYPE) >= sizeof(UnsignedBox::box_type)), int>::type = 0
>
UNSIGNED_TYPE UnsignedBox::toUnsigned() const;

第一个接受一个模板参数,第二个接受两个——尽管默认有一个。两者必须完全匹配。所以你需要两个声明:

template <typename UNSIGNED_TYPE,
typename = typename std::enable_if<
std::is_unsigned<UNSIGNED_TYPE>::value &&
sizeof(UNSIGNED_TYPE) >= sizeof(UnsignedBox::box_type)
>::type>
UNSIGNED_TYPE toUnsigned() const;

template <typename UNSIGNED_TYPE,
typename = typename std::enable_if<
std::is_unsigned<UNSIGNED_TYPE>::value &&
sizeof(UNSIGNED_TYPE) < sizeof(UnsignedBox::box_type)
>::type>
UNSIGNED_TYPE toUnsigned() const;

然后是两个定义。这本身也不起作用,因为我们有效地重新定义了默认模板参数,因此您需要对返回类型进行 SFINAE,例如:

template <typename UNSIGNED_TYPE>
typename std::enable_if<
std::is_unsigned<UNSIGNED_TYPE>::value &&
sizeof(UNSIGNED_TYPE) >= sizeof(UnsignedBox::box_type),
UNSIGNED_TYPE>::type
toUnsigned() const;


template <typename UNSIGNED_TYPE>
typename std::enable_if<
std::is_unsigned<UNSIGNED_TYPE>::value &&
sizeof(UNSIGNED_TYPE) < sizeof(UnsignedBox::box_type),
UNSIGNED_TYPE>::type
toUnsigned() const;

尽管将一个toUnsigned()转发到基于sizeof的其他两个成员函数可能更简单:

template <typename UNSIGNED_TYPE,
typename = typename std::enable_if<std::is_unsigned<UNSIGNED_TYPE>::value>::type>
UNSIGNED_TYPE toUnsigned() const {
return toUnsigned<UNSIGNED_TYPE>(
std::integral_constant<bool,
(sizeof(UNSIGNED_TYPE) >= sizeof(UnsignedBox::box_type))>{});
}

template <typename UNSIGNED_TYPE>
UNSIGNED_TYPE toUnsigned(std::true_type /* bigger */);

template <typename UNSIGNED_TYPE>
UNSIGNED_TYPE toUnsigned(std::false_type /* smaller */);

关于c++ - 使用 std::enable_if<> 的模板特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30830997/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com