gpt4 book ai didi

c++ - 如何在 C++11 中为 SFINAE 和静态断言定义约束

转载 作者:搜寻专家 更新时间:2023-10-31 00:25:38 25 4
gpt4 key购买 nike

我正在尝试使用模板进行序列化/反序列化,现在可以正常工作了。显然,在实现它时,我遇到了很多麻烦,有数百条编译器错误日志。在进一步扩展我的库之前,我想使用 SFINAE(到目前为止我很少使用它)和 static_asserts 来稍微保护它。

不要再弄乱我的库了,我正在沙箱中训练:

http://coliru.stacked-crooked.com/a/9eb4eaefaac90fc0

我想定义几个谓词:

  • is_a_base 检查从 Base 派生的对象。
  • is_insertable & is_extractable 检查是否已为此类型定义了 operator>> 和 operator<<。

我希望能够将这些谓词用于 SFINAE 特化和 static_assert。

#include <sstream>
#include <iostream>

//forward declaration
class Base;

//"Template typedef" to check predicates
template <typename T>
using is_a_Base = typename std::enable_if<std::is_base_of<Base, T>::value, void>::type;

template <typename T, typename is = std::istream>
using is_extractable = decltype (is{} >> T{});

template <typename T, typename os = std::ostream>
using is_insertable = decltype (os{} << T{});

//Test classes
class Base{
public:
std::string getStr(){ return "Base.getStr()";}
};
class Derived: public Base {};

class Other{};

//A template class with its specializations with SFINAE
template <typename T, typename Enable = void>
class C{
public:
static void f(T& o){
std::cout << "f<T> default !" << std::endl;
}
};

template<typename T>
class C<T, is_a_Base<T>>
{
public:
static void f (T& o)
{
std::cout << "f<is_a_A>() ! " << o.getStr() << std::endl;
}
};

template<typename T>
class C<T, is_insertable<T> >
{
public:
static void f (T& o)
{
std::cout << "f<is_insertable() ! " << o << std::endl;
}
};


template<typename T>
std::string g(T& ref)
{
//static_assert(is_a_Base<T>, "T is not a Base"); //can't figure out the syntax here
return ref.getStr();
}



int main(){
Base a;
Derived b;
int myint = 1;
std::string str="toto";

Other oops;


C<Base>::f(a);
C<Derived>::f(b);
C<int>::f(myint); //Not calling is_insertable ??
C<std::string>::f(str); //Not calling is_insertable ??
C<Other>::f(oops);

std::cout << "g:" << g(a) << std::endl;
//std::cout << "g:" << g(oops) << std::endl; //should be blasted by the static assert
}

结果:

f<is_a_A>() ! Base.getStr()
f<is_a_A>() ! Base.getStr()
f<T> default !
f<T> default !
f<T> default !
g:Base.getStr()

到目前为止,is_a_base 正在为 SFINAE 工作。但是,is_insertable 不适用于 int 和 string 变量?我也不知道如何正确地将 is_a_base 谓词重用到我的断言语句中。

(由于我受限于不支持超过 C++11 的交叉编译器,我无法利用 C++14 及更高版本的优势。)

最佳答案

您正在使用 SFINAE 选择 C 的特化通过默认参数 void .这意味着特化的签名必须正确替换,但产生void用于选择专业。就目前而言,您的流特征:

template <typename T, typename is = std::istream>
using is_extractable = decltype (is{} >> T{});

template <typename T, typename os = std::ostream>
using is_insertable = decltype (os{} << T{});

... 实际上从 operator >> 产生返回类型(分别为 << ),通常是 is & (分别为 os &)。自is_...以来,您的命名也有点困惑暗示一个 bool 值,但它们不是。因此我建议修复:

模板

using enable_if_base = typename std::enable_if<std::is_base_of<Base, T>::value>::type;
// `void` is the default already ^

template <typename T, typename is = std::istream>
using enable_if_extractable = decltype (std::declval<is &>() >> std::declval<T &>(), void());
// ^^^^^^^^

template <typename T, typename os = std::ostream>
using enable_if_insertable = decltype (std::declval<os &>() << std::declval<T const &>(), void());
// ^^^^^^^^

请注意,我还替换了 T{}具有适当资格的std::declval s,因为你不能假设相关类型实际上是默认可构造的——事实上,std::istreamstd::ostream不是。

关于c++ - 如何在 C++11 中为 SFINAE 和静态断言定义约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55498442/

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