替换失败不是错误。这是一种C ++编程技术,允许模板验证有关其模板参数的属性,从而允许在某些类型的对象可用时使用不同的特化。
我有一个头文件,其功能在很大程度上依赖于SFINAE的成功。在目前的 g++ 4.6 中,它按预期工作。我是否应该假设,我的代码将以同样的方式无缝运行......
是否存在允许在类外部定义 method1 的语法,或者这对 SFINAE 不友好? #包括 模板 结构样本类{ // 这个
我(我认为)需要什么 如何定义一个类型特征来检查对于类型 T 是否声明了函数 ::foo(T) ? 我发现很难的是以 SFINAE 友好的方式拥有 ::foo 。例如...
是否有一个C++20概念,当使用某个库中的函数时会调用该概念?
我希望对某个库中的函数的所有调用都包含对我的函数的调用。 例如,每当调用库 中的函数时,我的函数 log() 都是...
考虑以下基本类模板: #包括 模板< typename T > A类{ 民众: A() = 默认值; T 对象; 模板< typename U = T, type...
我被 C++03 编译器困住了,并试图从(智能指针)模板类中消除“void”类型的函数。 MRE(从课程中删除所有非必要信息): 温度...
我打算将我的问题作为以下问题的后续:我们如何将 void_t 用于 SFINAE?我明白了 void_t 是如何使用的。我不明白为什么有必要。 让我们以那个问题为例...
在 C++14 中是否可能(因此没有约束、require 或折叠表达式,但有 SFINAE)对类模板进行部分模板特化 模板 基因类...
我有这样的代码(类似“太空飞船”的运算符)。 模板 int 比较器(const T &a, const T &b){ 如果(a< b){ return -1; }else if (a >b){
有人可以帮助我理解为什么下面的代码无法编译。 #包括 #包括 模板 无效 foo(T &&va...
我想检查是否存在某种模板专门化,其中未定义一般情况。 鉴于: 模板 结构 A; // 通用定义未定义 圣殿...
一种编译时方法来测试模板参数 T 是否定义了自己的(静态)方法,而不考虑 T 的基类定义的方法
我在代码中使用静态类版本 CRTP(奇怪的重复模板模式)。那是: // 使用 CRTP 的基类模板 模板 基类{ 民众: // 静态
这就是我想做的: 模板 结构模型 { 矢量 顶点; #if T 有一个 .normal 成员 无效变换(矩阵 m ) {
C++ 标准中声明模板参数推导的类型推导失败不是错误 (SFINAE) 的确切引用是什么?
以下来自 CPPreference 的引用很清楚: 此规则适用于函数模板的重载解析期间:当用显式指定或推导的类型替换模板参数时...
在构造函数中使用SFINAE,检查成员类型的构造函数是否存在
#包括 #包括 结构体A { A(整数){} }; 模板 auto make_A(const Args&... args) -> decltype(A(args...)) { 返回 A(ar...
我正在开发一个 C++ 项目,我想将事件分派到不同的模块。我有一个基本事件类和几个派生事件类型(EventA、EventB、EventC)。我的模块继承自临时...
SFINAE 构造函数中存在 `is_constructible` 问题
我无法理解为什么以下代码无法编译: #包括 #包括 #包括 枚举类错误 { 好=0, 挪威克朗=1 };
std::void_t 与 SFINAE 用法中的自定义函数
#包括 模板 结构体CheckX { 使用 TypeOfX = decltype(T::x); 使用值=无效; }; 结构A { }; 结构B { 整数x; }; 模板 #include <iostream> template <typename T> struct CheckX { using TypeOfX = decltype(T::x); using Value = void; }; struct A { }; struct B { int x; }; template <typename T , typename = void> struct Res { static constexpr bool value = false; }; // template <typename T> // struct Res<T , std::void_t<decltype(T::x)>> // { // static constexpr bool value = true; // }; template <typename T> struct Res<T , typename CheckX<T>::Value> { static constexpr bool value = true; }; int main() { std::cout << Res<B>::value << '\n'; std::cout << Res<A>::value << '\n'; } 这些是我想要实现一个检查器的代码,该检查器检查结构中是否存在成员x。我注意到使用自定义 CheckX 会导致编译失败,而 std 库 std::void_t 会完成这项工作。我在这里缺少什么? 第一个版本(带有 void_t)完全按照您的预期工作: 对于类 A,当考虑此 std::void_t<decltype(T::x)> 时,A::x 会导致替换失败(由于缺少 Res)。 这是经典的 SFINAE。 因此,这个版本的 Res 被丢弃,留下默认的 Res 和 value = false。 第二个版本(带有CheckX<T>)甚至没有进入SFINAE阶段Res: 为了检查 CheckX<T>::Value,首先将 CheckX<T> 实例化。作为其中的一部分,using TypeOfX = decltype(T::x)被解析,并且由于A不包含x,decltype(T::x)会触发错误。 解析 using 的这个 A 声明不是 Res 的 SFINAE 的一部分(它是在初步阶段完成的)。 注意,这种场景正是std::void_t的确切目的: 将任何类型的序列映射到该类型的实用程序元函数 空白。 此元函数是利用 SFINAE 先验的便捷方法 C++20 的概念,特别是有条件删除 根据表达式是否为候选集的函数 在未评估的上下文中有效(例如 decltype 的操作数 表达式),允许存在单独的函数重载或 基于支持的操作的专业化。 (重点是我的) 另请参阅 cppreference.com 页面中的 struct has_type_member 示例。
我有一个检查器函数,它使用requires关键字来检测目标函数是否已定义。我想让它与 C++17 一起使用,所以我将检查器从使用 require 切换为使用
是否可以从迭代器类型中检测容器类型? 例如, #包括 int main(){ static_assert(std::is_same< container_of 是否可以从迭代器类型中检测容器类型? 例如, #include<traits> int main(){ static_assert(std::is_same< container_of<std::vector<double>::iterator>::type, std::vector<double>>{}); static_assert(std::is_same< container_of<std::list<int>::iterator>::type, std::list<int>>{}); } (当然,某些迭代器类型不会提供容器(或不会提供唯一的容器),例如原始指针或流迭代器,但在这些情况下,它可能会软SFINAE失败。) 第一次尝试是 template<class T, template<class> class Cont> Cont<T> aux(typename Cont<T>::iterator it); template<class Iterator> struct container_of{ using type = decltype(aux(Iterator{})); }; 但是,它不起作用,因为编译器无法检测到 T 的类型(它不在可扣除的上下文中)。 动机:我想检测迭代器的关联容器是否有 .data() 成员。 不要让你的基元成为迭代器,而让你的基元成为一个范围。 template<class It, bool Contiguous, class D=void> struct range_t { using Self = std::conditional< !std::is_same<D, void>, D, range_t >; It b, e; It begin() const { return b; } It end() const { return e; } Self without_front( std::size_t i = 1 ) const { return {std::next(begin(), i), end()}; } Self without_back( std::size_t i = 1 ) const { return {begin(), std::prev(end(), i)}; } bool empty() const { return begin()==end(); } std::size_t size() const { return std::distance( begin(), end() ); } }; template<class It> struct range_t<It, true, void>: range_t<It, false, range_t<It, true>> { using Base = range_t<It, false, range_t<It, true>>; range_t( It b, It e ):Base(b,e) {} auto* data() const { if (empty()) return nullptr; return std::addressof(*this->begin()); } } }; (手动)跟踪哪些容器是连续的: template<class T, class=void> struct is_contiguous_container : std::false_type{}; template<class T> struct is_contiguous_container<T const, void> : is_contiguous_container<T> {}; template<class T> struct is_contiguous_container<T volatile, void> : is_contiguous_container<T> {}; template<class T> struct is_contiguous_container<T const volatile, void> : is_contiguous_container<T> {}; template<class T> struct is_contiguous_container<T, std::enable_if_t< has_data_ptr<T>{} >>: std::true_type{}; template<class T, std::size_t N> struct is_contiguous_container<T[N],void> : std::true_type{}; 连续的容器是数组、std::array和std::vector,所以不需要跟踪太多。 range_t< ?, true, ? > 也是连续的。 只要写 has_data_ptr,当且仅当 T.data() 返回一个指向非 void 的指针时,这是正确的。 template<class C> auto range( C&& c ) { using std:begin; using std::end; auto b = begin(c), e = end(c); using It = decltype(b); using R = range_t<It, is_contiguous_container<std::remove_reference_t<C>>{}>; return R{ b, e }; } range 现在可以智能地将容器转换为 range_t,并跟踪它是否连续。 range_t支持r.without_front( r.size()/2 )分而治之。 当范围是连续的时,只需对其调用 .data() 即可。 如果不是,请不要。 在您的应用程序中,如果您只想知道容器是否有 .data() 成员,检查它是否是随机访问可能就足够了(使用 std::iterator_traits<Iter>::iterator_category())。 否则,我认为您可能可以结合使用以下技术:如何检查两种类型是否来自同一模板化类以及每个标准容器类型的部分专业化。 或者等待c++17,它有一个新的连续迭代器概念:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html 我现在正在做的是手动注册所有(实际上是一些)连续的迭代器。 由于我总是需要结合某种方法来提取原始指针,因此我直接编写了一个名为 data 的函数来返回指针。 代码并不有趣,它考虑了std::vector<>::iterator,std::basric_string<>::iterator,为了说明(以表明它总是不完整的)我还添加了boost::static_vector<>,原始指针和任何可转换为指针的东西。 (boost::array<>::iterator、std::array<>::iterator和begin/end(std::valarray)被有效地包含在内,因为迭代器是指针)。 我还必须包括 const_iterator 案例。 #include<type_traits> #include<vector> // the code below needs to know about std::vector #include<boost/container/static_vector.hpp> // ... and all possible contigous containers :( template< class ContiguousIterator, // well ProbablyContiguos typename = std::enable_if_t< /**/std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{} or std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::const_iterator>{} or std::is_same<ContiguousIterator, typename std::basic_string<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{} or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::iterator>{} or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::const_iterator>{} // many many other possible iterators :( or std::is_pointer<ContiguousIterator>{} or std::is_constructible<typename std::iterator_traits<ContiguousIterator>::pointer, ContiguousIterator>{} > > typename std::iterator_traits<ContiguousIterator>::pointer data(ContiguousIterator const& it){return std::addressof(*it);} int main(){ std::vector<double> v(30); v[0] = 10.; assert( *data(v.begin()) == 10. ); } 欢迎反馈。