模板标签用于多种上下文:通用编程(尤其是C ++),以及使用模板引擎生成数据/文档。在实现繁重的问题上使用此标记时 - 标记实现编写的代码语言。
有一个非常相似的问题,但我不明白如何将解决方法应用到我的代码中。更多的是关于实现不同容器类型之间的通用性:Visual C++ 无法...
在分析大型 AngularJS 应用程序时,我开始跟踪 $templateCache。 https://docs.angularjs.org/api/ng/service/$templateCache 这个物体是什么? 它是否按原样存储部分内容
我想要一个可调用的概念,以避免缩小转换和切片。在第一次尝试编写它时,我发现对 std::invocable 的天真使用会拒绝
以下代码会在注释掉概念时打印所有内容: #包括 #包括 #包括 #包括 模板 以下代码在注释掉概念时打印所有内容: #include <cstdint> #include <concepts> #include <print> #include <type_traits> template<typename T> struct ValueHolder { using ValueType = T; T value; }; template< typename Value, typename T = std::remove_reference_t<Value>::ValueType, // typename Arg, typename Callable > // requires // std::invocable<Callable, T> // std::assignable_from<Arg, T> // std::convertible_to<T, Arg> // && std::invocable<Callable, Arg> void callOnValue(Value&& val, Callable&& callable) { std::forward<Callable>(callable)(std::forward<Value>(val).value); } void printI32(std::int32_t) { std::println("i32"); } void printI32Ref(std::int32_t&) { std::println("i32&"); } void printI32RefRef(std::int32_t&&) { std::println("i32&&"); } void printConstI32Ref(const std::int32_t &) { std::println("const i32&"); } void printI16(std::int16_t) { std::println("i16"); } void printI64(std::int64_t) { std::println("i64"); } int main() { ValueHolder i{static_cast<std::int32_t>(42)}; callOnValue(i, printI32); callOnValue(i, printI32Ref); callOnValue(ValueHolder{static_cast<std::int32_t>(42)}, printI32RefRef); const auto ci{i}; callOnValue(ci, printI32); callOnValue(ci, printConstI32Ref); callOnValue(i, printI16); callOnValue(i, printI64); } 取消评论 requires std::invocable<Callable, T> 无法拨打电话printIntRef。取消注释 Arg 以及 std::assignable_from 或 std::convertible_to 会导致无法推断出 Arg。 callable上的什么概念将允许重现所有默认传递(即callable接受按值传递、通过 const ref、通过左值的 ref 和通过右值的 ref-ref 传递)? 如果我想要所有传递但又想防止缩小转换(printI16不能编译,printI64可以)怎么办? 如果T中的ValueHolder是Derived&或Derived*,如何约束callable为逆变,即接受Base&或Base*? 如何防止切片(按值从Derived到Base)? 问题在于你对自己真正想做的事情感到困惑。 首先,callOnValue应该是这样的 void callOnValue(Value&& val, Callable&& callable) { std::forward<Callable>(callable)(std::forward_like<Value>(val.value)); } 否则,您会在正确转发会员值时遇到问题。 std::forward_like 来自 C++23,因此您可以使用替代实现: template<class T, class U> constexpr auto&& forward_like(U&& x) noexcept { constexpr bool is_adding_const = std::is_const_v<std::remove_reference_t<T>>; if constexpr (std::is_lvalue_reference_v<T&&>) { if constexpr (is_adding_const) return std::as_const(x); else return static_cast<U&>(x); } else { if constexpr (is_adding_const) return std::move(std::as_const(x)); else return std::move(x); } } 第二个问题是模板中的Value可能是常量,所以要引用ValueType的Value最好这样写。 typename T = std::remove_cvref_t<Value>::ValueType 第三个问题是如何测试是否可以正确调用。怎么做呢?您需要将 Value 的特征复制到 T 并测试结果的可调用性。您可以通过自定义类型特征来做到这一点: template<class T, class U> struct copy_traits { using type = decltype(forward_like<T>(std::declval<U>())); }; template<class T, class U> using copy_traits_t = typename copy_traits<T,U>::type; 其中 forward_like 如上所述,并测试其可调用性 by std::invocable<Callable, copy_traits_t<Value, T> > 你会得到这样的代码: #include <cstdint> #include <concepts> #include <iostream> #include <type_traits> #include <utility> template<typename T> struct ValueHolder { using ValueType = T; T value; }; template<class T, class U> constexpr auto&& forward_like(U&& x) noexcept { constexpr bool is_adding_const = std::is_const_v<std::remove_reference_t<T>>; if constexpr (std::is_lvalue_reference_v<T&&>) { if constexpr (is_adding_const) return std::as_const(x); else return static_cast<U&>(x); } else { if constexpr (is_adding_const) return std::move(std::as_const(x)); else return std::move(x); } } template<class T, class U> struct copy_traits { using type = decltype(forward_like<T>(std::declval<U>())); }; template<class T, class U> using copy_traits_t = typename copy_traits<T,U>::type; template< typename Value, typename Callable, typename T = std::remove_cvref_t<Value>::ValueType > requires (std::invocable<Callable, copy_traits_t<Value, T> >) void callOnValue(Value&& val, Callable&& callable) { std::forward<Callable>(callable)(forward_like<Value>(val.value)); } void printI32(std::int32_t) { std::cout << "i32\n"; } void printI32Ref(std::int32_t&) { std::cout << "i32&\n"; } void printI32RefRef(std::int32_t&&) {std::cout << "i32&&\n"; } void printConstI32Ref(const std::int32_t &) {std::cout << "const i32&\n"; } void printI16(std::int16_t) { std::cout << "i16\n"; } void printI64(std::int64_t) { std::cout << "i16\n"; } int main() { ValueHolder i{static_cast<std::int32_t>(42)}; callOnValue(i, printI32); callOnValue(i, printI32Ref); callOnValue(ValueHolder{static_cast<std::int32_t>(42)}, printI32RefRef); const auto ci{i}; callOnValue(ci, printI32); callOnValue(ci, printConstI32Ref); callOnValue(i, printI16); callOnValue(i, printI64); } 或者,您也可以编写一个自定义概念: requires (requires (Value&& val, Callable&& callable) { {std::forward<Callable>(callable)(forward_like<Value>(val.value))}; })
是否可以在概念中使用`std::index_sequence`?
假设您想要定义一个概念来检查变体的所有替代项是否都可以转换为 int。你可以这样做: 模板 概念 ConvertibleToInt = std::
如何实现 Android Auto 模板,以在驾驶时实现按字母搜索?
我想为 Android Auto 制作一个应用程序,用户应该能够在驾驶过程中按名称搜索一长串项目。显然,开车时键盘被挡住了,我知道...
如何获取 JavaScript/TypeScript 中某个类型的字符串?
在 C# 中你可以这样做: 字符串 typeName = typeof(int).FullName; typeName 的值为 System.Int32。 (参考这个问题供参考)。 所以,我的问题是,如何...
上下文: 该程序应该有一个单个链接列表的模板,您可以在其中通过密钥查找信息。我的意思是实现一个拆分函数,它将接受一个源序列,s...
上下文: 该程序应该有一个单个链接列表的模板,您可以在其中通过密钥查找信息。我的意思是实现一个拆分函数,它将接受一个源序列,s...
上下文: 该程序应该有一个单个链接列表的模板,您可以在其中通过密钥查找信息。我的意思是实现一个拆分函数,它将接受一个源序列,s...
您知道 boost::fusion 库使用的任何好的资源/文章/示例吗? Boost Fusion 看起来非常有趣,我想我了解它的工作原理以及如何使用基础知识,但我看起来......
我有一些模板函数,只有一个模板参数。 // 添加.cpp 模板 T 添加(T a, T b) { // 做某事 } // 函数1.cpp 模板 void func1(在...
函数重载解析不考虑返回类型,但是我在 Cppreference 上遇到了一段代码 除了 SFINAE 之外,这里的重载解析是如何进行的: #包括 函数重载解析不考虑返回类型,但是我在Cppreference上遇到了一段代码 SFINAE 不谈,这里的重载解析是如何发生的: #include <iostream> // This overload is added to the set of overloads if C is // a class or reference-to-class type and F is a pointer to member function of C template<class C, class F> auto test(C c, F f) -> decltype((void)(c.*f)(), void()) { std::cout << "(1) Class/class reference overload called\n"; } // This overload is added to the set of overloads if C is a // pointer-to-class type and F is a pointer to member function of C template<class C, class F> auto test(C c, F f) -> decltype((void)((c->*f)()), void()) { std::cout << "(2) Pointer overload called\n"; } // This overload is always in the set of overloads: ellipsis // parameter has the lowest ranking for overload resolution void test(...) { std::cout << "(3) Catch-all overload called\n"; } int main() { struct X { void f() {} }; X x; X& rx = x; test(x, &X::f); // (1) test(rx, &X::f); // (1), creates a copy of x test(&x, &X::f); // (2) test(42, 1337); // (3) } 我已经查过了。这段代码有效。那么,这里是否使用尾随返回类型来进行重载解析? 重载解析不考虑返回类型 它们意味着,给定几个可行的重载,它们不会根据返回类型(是否与返回值的使用方式匹配,等等)消除歧义。 另一方面,当重载由于 SFINAE 错误而被拒绝时,错误是在返回类型中还是在其他地方并不重要。
我有一个已创建的 Google 表格,并希望为其创建多个实例。这些副本将由最终用户(其他 Google 帐户)创建,如下所示。 我使用带有编辑功能的下拉菜单
有没有办法为模板类提供默认值? 例如。假设我有一个 TimeSeries 类,它是模板化的。 我有一个名为 Foo() 的函数,它返回 T。 模板 ...
我用测试用例编写了这个类型特征: 模板 结构 is_serialized: false_type {}; 模板 结构是_可序列化< T,
我试图通过单击选项卡集上的图标来渲染选项卡主体部分内的数据。这是我的初始成功渲染视图的屏幕截图: 但是当我单击新的选项卡集图标时...
我正在 bool MyClass::Initialize() 方法中读取带有 MyClass 类的二进制文件,以读取存储在 std::ifstream MyClass::in_ 中的二进制文件的第一个块。 我知道垃圾箱的结构...
忽略候选模板:无法使用 std::variant 推断模板参数 'T'
我一直在阅读与此错误相关的所有其他问题,但找不到适合我的情况的内容(或者我没有正确理解它们)。 我提供了一个班级假期的最小示例...