替换失败不是错误。这是一种C ++编程技术,允许模板验证有关其模板参数的属性,从而允许在某些类型的对象可用时使用不同的特化。
是否可以从迭代器类型中检测容器类型? 例如, #包括 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. ); } 欢迎反馈。
示例 许多以下阶层的消费者 A类{ 双a; 无效转储(){ std::ofstream ooo("dump.txt");哦<< A.a << "\n"; ooo.close(); } }; wi...
基于用户定义的输入类型类别的C++函数调度(C++11/14友好)
我想根据用户定义的输入类型“标签”来调度函数。例如,我定义了一个名为 SomeSpecificObjectType 的标签,并在 Object 类中将此类标记为
GCC 14 中的 C++ 模糊成员函数模板解析与非成员函数模板解析,但在之前的 GCC 版本中没有解析
以下代码可以在 GCC 13 及更早版本中正常编译,但 GCC 14.1 会产生“模糊重载”错误。这是编译器还是代码问题,更务实的是,我可以让 co...
我有几个重载函数,如下所示: 模板 结构点{ std::enable_if_t,T> x,y; }; //...
我有以下代码,它接受一个值并返回 0 和该值之间的随机值: 模板 类型名 std::enable_if::value>::type
如何使 `if constexpr` 变得对 SFINAE 友好?
我有一个使用“经典”SFINAE 的代码。 template auto power(M const& elem) -> decltype(std::norm(elem)) { return std::norm(elem); } 模板 我有一个使用“经典”SFINAE 的代码。 template<class M> auto power(M const& elem) -> decltype(std::norm(elem)) { return std::norm(elem); } template<class M, class = std::enable_if_t<(M::rank::value >= 1)>> auto power(M const& array) { return accumulate(begin(array), end(array), 0.0, [](auto const& alpha, auto const& omega) { return alpha + power(omega); }); } 这是一个递归(跨维度或等级)“幂”函数,通过计算较低维度子元素的幂,最终给出元素的平方和。 现代 C++ 鼓励使用 if constexpr 以避免使用 SFINAE,如下所示。 template<class M> auto power(M const& array) { if constexpr(M::rank::value >= 1) { return accumulate(begin(array), end(array), 0.0, [](auto const& alpha, auto const& omega) { return alpha + power(omega); }); } else { return std::norm(array); } } 问题在于,if constexpr中的表达式似乎首先必须是有效的表达式。 元素没有名为 rank 的成员类型,因此会出现编译错误。 如果表达式无效,是否有技巧可以使 if constexpr 谓词? C++20 及更新版本: if constexpr (requires{requires std::bool_constant</*condition*/>::value;}) 还有一个不太详细的选项: if constexpr (requires{requires /*condition*/;}) 但是后者更糟糕,因为如果编译时不知道条件,它会导致硬错误,而前者只是返回 false。 前者在标准库中使用(另请参阅在嵌套需求中,为什么使用requires bool_constant<X>::value;而不是requires X;?)。 C++17: 使用检测惯用语: #include <type_traits> namespace detail { template <typename ...P> struct void_type {using type = void;}; template <typename DummyVoid, template <typename...> typename A, typename ...B> struct is_detected : std::false_type {}; template <template <typename...> typename A, typename ...B> struct is_detected<typename void_type<A<B...>>::type, A, B...> : std::true_type {}; } template <template <typename...> typename A, typename ...B> inline constexpr bool is_detected = detail::is_detected<void, A, B...>::value; 然后: template <typename M> using CheckRank = std::enable_if_t<M::rank::value >= 1>; if constexpr (is_detected<CheckRank, M>)
我有一个使用“经典”SFINAE 的代码。 template auto power(M const& elem) -> decltype(std::norm(elem)) { return std::norm(elem); } 模板 我有一个使用“经典”SFINAE 的代码。 template<class M> auto power(M const& elem) -> decltype(std::norm(elem)) { return std::norm(elem); } template<class M, class = std::enable_if_t<(M::rank::value >= 1)>> auto power(M const& array) { return accumulate(begin(array), end(array), 0.0, [](auto const& alpha, auto const& omega) { return alpha + power(omega); }); } 这是一个递归(跨维度或等级)“幂”函数,通过计算较低维度子元素的幂,最终给出元素的平方和。 现代 C++ 鼓励使用 if constexpr 以避免使用 SFINAE,如下所示。 template<class M> auto power(M const& array) { if constexpr(M::rank::value >= 1) { return accumulate(begin(array), end(array), 0.0, [](auto const& alpha, auto const& omega) { return alpha + power(omega); }); } else { return std::norm(array); } } 问题在于,if constexpr中的表达式似乎首先必须是有效的表达式。 元素没有名为 rank 的成员类型,因此会出现编译错误。 如果表达式无效,是否有技巧可以使 if constexpr 谓词? if constexpr (requires{requires std::bool_constant</*condition*/>::value;}) 还有一个不太详细的选项: if constexpr (requires{requires /*condition*/;}) 但是后者更糟糕,因为如果编译时不知道条件,它会导致硬错误,而前者只是返回 false。
我正在尝试习惯一些 tmp 概念。 这是一种检查 2 种类型是否可分配的解决方案: 这是最重要的部分: 模板 班级
有没有办法检查函数(特定签名)是否存在,无论它是否是模板化的? 例如: 模板 A级 { 民众: 模板 &l...
这个简单的 has-member SFINAE 技术符合吗?
我正在使用一种简单的(不是特别新的)技术来检查特定名称和类型的类成员是否存在。 以下代码在 Clang 中编译良好,但 MSVC 报告
有没有办法检查函数是否存在,无论它是否是模板化的? 例如: 模板 A级 { 民众: 模板 ...
我想实现一个流式日志库。 我创建了一个 Log_t 类来缓冲日志条目,并对其进行实际输出 毁掉了,像这样: 类 Log_t: 公共 std::ostringstream { 是...
SFINAE 工作正常,但概念约束在类模板实例化中进行了模糊的推论
我正在编写一个曲线类,它可以采用算术类型或算术数组类型作为模板参数。 对于算术数组曲线,本身需要一个包含算术c的数组成员...
模板函数 func 设计为可在任何地方使用。它对任何 T 都有相同的函数体。我只想写一次它的函数体。但功能取决于定义类型 模板功能func<T>设计用于任何地方。对于任何T,它都有相同的函数体。 我只想写一次它的主体。但该功能取决于 type<T> 的定义才能正常工作,并且在某些情况下没有 type<T> 的定义。请参阅以下示例(C++17 中): /// type.h #include <stddef.h> #include <stdint.h> #include <type_traits> template<typename T, typename = void> struct type; template<typename T> size_t func() { return type<T>::magic; } template<typename T> struct type<T, std::enable_if_t<std::is_arithmetic_v<T>>> { static constexpr size_t magic = sizeof(T) * 2; }; /// my_type.h struct MyStruct { int a; static void Dummy(); }; /// my_type.cpp #include "my_type.h" #include "type.h" template<> struct type<MyStruct> { static constexpr size_t magic = 123; }; void MyStruct::Dummy() { (void)func<MyStruct>(); } /// main.cpp #include "my_type.h" #include "type.h" int main(int argc, char **argv) { func<int>(); // OK func<MyStruct>(); // Error } 我怎样才能做到这一点: 只写一次func<T>的正文。 当 func<T> 不完整时,可以调用 type<T>。 注意:有一个 Dummy 函数,用于强制编译器为 func<MyStruct> 生成代码,以便链接器满意。 使用显式实例化: /// my_type.h struct MyStruct { int a; }; // Explicit instantiation declaration extern template size_t func<MyStruct>(); /// my_type.cpp #include "my_type.h" #include "type.h" template<> struct type<MyStruct> { static constexpr size_t magic = 123; }; // Explicit instantiation definition template size_t func<MyStruct>(); 声明它存在于头文件中(因此包含头文件的任何内容都可以看到声明,而不是尝试实例化模板本身),并在类型完成后在源文件中定义它。 您也不再需要Dummy,无论如何也不能保证它能工作。
在C++11中使用SFINAE在具有相同签名的两个函数之间进行选择
我尝试使用 c++11 中的 SFINAE 在具有相同签名但不同主体的两个函数之间进行选择,基于给定 T 类型内应该有或没有 typedef 的事实。对于前...
最小工作示例: #包括 #包括 模板 struct is_array : std::false_type {}; 模板 结构 is_arr...
最小实现: #包括 #包括 模板 自动universal_ref(T&& arr) { for (自动 && v : arr) std::cout <&...
有些事情对我来说不太顺利。这是声明只接受浮点模板参数的类的方法吗? 模板 有些事情对我来说不太顺利。这是声明一个只接受浮点模板参数的类的方法吗? template <typename T, swift::enable_if<std::is_floating_point<T>::value> = nullptr> class my_float; 我无法在此类之外定义方法。无法编译,不知道为什么 您还可以使用static_assert毒害无效类型。 template <typename T> class my_float { static_assert(std::is_floating_point<T>::value, "T is not a floating point type"); // . . . }; 我认为这更直接一些。 使用其他任何一种方法,例如 template <typename T, bool = std::is_floating_point<T>::value> class my_float; template <typename T> class my_float<T, true> { /* . . . */ }; my_float<int,true> 是一个有效的表达式。我并不是说这是一个不好的方法,但如果你想避免这种情况,你必须封装 my_float<typename,bool> 在另一个模板中,以避免暴露 bool 模板参数。 嗯...不完全是SFINAE...但也许,使用模板专业化?如下? template <typename T, bool = std::is_floating_point<T>::value> class my_float; template <typename T> class my_float<T, true> { // ... }; 如果你真的想使用SFINAE,你可以写 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type> class my_float { // ... }; 或者也(观察示例中没有的指针) template <typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr> class my_float // ------------------------------------------------^ { }; --编辑-- 按照 Yakk 的建议(谢谢!),您可以混合 SFINAE 和模板专业化,为不同类型的群体开发不同版本的类。 例如以下my_class template <typename T, typename = void> class my_class; template <typename T> class my_class<T, typename std::enable_if<std::is_floating_point<T>::value>::type> { // ... }; template <typename T> class my_class<T, typename std::enable_if<std::is_integral<T>::value>::type> { // ... }; 开发有两个版本(两个不同的部分特化),第一个版本用于浮点类型,第二个版本用于整数类型。并且可以轻松扩展。 确实,这样的东西对我有用(感谢SU3的回答)。 template<typename T, bool B = false> struct enable_if {}; template<typename T> struct enable_if<T, true> { static const bool value = true; }; template<typename T, bool b = enable_if<T,is_allowed<T>::value>::value > class Timer{ void start(); }; template<typename T, bool b> void Timer<T,b>::start() { \* *** \*} 我发布这个答案是因为我不想使用部分专业化,而只想定义外部类的行为。 一个完整的可行示例: typedef std::integral_constant<bool, true> true_type; typedef std::integral_constant<bool, false> false_type; struct Time_unit { }; struct time_unit_seconds : public Time_unit { using type = std::chrono::seconds; }; struct time_unit_micro : public Time_unit { using type = std::chrono::microseconds; }; template<typename T, bool B = false> struct enable_if { }; template<typename T> struct enable_if<T, true> { const static bool value = true; }; template<typename T, bool b = enable_if<T, std::is_base_of<Time_unit, T>::value >::value> struct Timer { int start(); }; template<typename T, bool b> int Timer<T, b>::start() { return 1; } int main() { Timer<time_unit_seconds> t; Timer<time_unit_micro> t2; // Timer<double> t3; does not work ! return 0; }
最小工作示例: #包括 #包括 模板 struct is_array : std::false_type {}; 模板 结构 is_arr...