C 中的概念(即将推出的功能)的替代方法
What to use as replacement for concepts (upcoming feature) in C++?
c ?
您可能听说过C 中的概念。这是一项功能允许您指定模板类型的要求。
我正在寻找一种现在做到这一点的方法,而我发现的最好的是Stroustrup的书,他将谓词与static_assert一起使用:
template<typename Iter, typename Val>
Iter find(Iter b, Iter e, Val x)
{
static_assert(Input_iterator<Iter>(),"find(): Iter is not a Forward iterator");
// Rest of code...
}
请让我知道您是否使用其他方法或此方法是否出了点问题。
有一种C 03进行概念提供的一部分编译时间检查的方法。
检查是否提供了特定成员
概念可以定义如下(if(0)
用于在链接过程中抑制错误。(void)test#
用于抑制未使用的变量警告。):
template <class T>
struct ForwardIterator {
ForwardIterator() {
if(0) {
void (T::* test1) () = &T::operator++; (void)test1;
}
}
};
template <class T>
struct BidirectionalIterator {
BidirectionalIterator() {
if(0) {
ForwardIterator<T> requirement_1;
void (T::* test1) () = &T::operator--; (void)test1;
}
}
};
可以使用模板实例化在编译时间进行测试:
struct FooIterator {
void operator++() {}
};
template struct BidirectionalIterator<FooIterator>;
它具有给出编译错误的附加优势,即(一旦您习惯了它们),它比C 11的static_assert提供的读数要好得多。例如,GCC给出以下错误:
concept_test.cpp: In instantiation of ‘BidirectionalIterator<T>::BidirectionalIterator() [with T = FooIterator]’:
concept_test.cpp:24:17: required from here
concept_test.cpp:15:30: error: ‘operator--’ is not a member of ‘FooIterator’
void (T::* test1) () = &T::operator--; (void)test1;
^
甚至MSVC2010都会生成一个有用的编译错误,该错误包括模板参数t的哪些值引起了错误。对于static_asserts,它不这样做。
检查参数的类型和返回值
如果参数/返回类型取决于要测试的类,则测试类必须提供必要的Typedefs。例如,以下概念测试一类是否提供返回前进迭代器的开始和结束功能:
template <class T>
struct ForwardIterable {
ForwardIterable() {
if(0) {
ForwardIterator<typename T::Iterator> requirement_1;
typename T::Iterator (T::* test1) () = &T::begin; (void)test1;
typename T::Iterator (T::* test2) () = &T::end; (void)test2;
}
}
};
,它用如下(请注意,必需的Typedef):
struct SomeCollection {
typedef FooIterator Iterator;
Iterator begin();
Iterator end();
};
template struct ForwardIterable<SomeCollection>;
签名检查
此方法还广泛检查签名。在以下代码中,编译器将检测到modifyFooItem
的参数不应为const。
struct SomeFoo;
template <class T>
struct TestBar {
TestBar() {
if(0) {
int (T::* test1) (SomeFoo * item) = &T::modifyFooItem; (void)test1;
}
}
};
struct SomeBar {
int modifyFooItem(const SomeFoo * item) {}
};
template struct TestBar<SomeBar>;
它生成以下错误:
concept_test.cpp: In instantiation of ‘TestBar<T>::TestBar() [with T = SomeBar]’:
concept_test.cpp:61:17: required from here
concept_test.cpp:52:47: error: cannot convert ‘int (SomeBar::*)(const SomeFoo*)’ to ‘int (SomeBar::*)(SomeFoo*)’ in initialization
int (T::* test1) (SomeFoo * item) = &T::modifyFooItem; (void)test1;
好吧,我需要的几次类似概念的功能,我转向概念检查。这不是最漂亮的库,但似乎已经内置了很多东西。
我使用您的方法的唯一问题是,需要写所有特质类。我没有广泛使用它,但是大概已经为您提供了很多常见的事情。
检查概念的最佳方法是使用替代故障。但是,在C 98中,使用替换故障的检测相当有限。在C 11中,我们可以将替代失败与表达式更强大得多。C 11中的tick库提供了定义概念谓词的简单方法。例如,可以像这样写一个快速而肮脏的is_input_iterator
:
TICK_TRAIT(is_input_iterator,
std::is_copy_constructible<_>)
{
template<class I>
auto requires_(I&& i) -> TICK_VALID(
*i,
++i,
i++,
*i++
);
};
,然后tick还提供了一个 TICK_REQUIRES
宏来添加模板约束(只需照顾所有enable_if
样板),因此您可以像这样定义函数:
template<typename Iter, typename Val, TICK_REQUIRES(is_input_iterator<Iter>())>
Iter find(Iter b, Iter e, Val x)
{
// Rest of code...
}
理想情况下,您不想使用static_assert
,因为它会产生编译错误。因此,我们无法检测到find
是否在使用某些参数调用时是有效的,因为它会在无效时会产生编译器错误。
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何使用 C/C++ 和 system() 系统调用以外的其他方法在 Linux 中获取文件功能?
- C++中SFINAE的功能方法
- 如何定义和设置指向模板类方法的功能指针
- 将C 方法作为功能指针传递
- 寻找一种加速功能的方法
- 单位测试私人方法通过使其自由功能
- 如何通过功能指针调用派生方法
- 在具有多个返回点的功能中清理的正确方法
- C 模板功能是否有任何方法可以采用n个参数
- 是否有一种方法可以避免在RVALUE和LVALUE参考中创建功能时避免重复的代码
- 从功能指针调用方法
- 早期回报构成功能的最简短方法
- 实现交换/复制功能:有没有更好的方法
- 正确的方法将功能限制为特定数据类型
- 测试模拟功能的最佳方法
- C 获得超载成员功能指针的通用方法
- 有什么方法可以将此功能分开并插入空间
- C :不同类型的模板功能(方法)的自定义返回值
- 如何使用Playound()或任何基本功能/方法同时播放超过1个