C++折叠表达式:替换特定类型并转发其余类型的实现方法
折叠表达式中针对特定类型替换转发逻辑的实现方法
问题背景
我尝试在fold expression(折叠表达式)中对特定类型做替换处理,其余所有类型直接执行转发,多次尝试均未成功:
- 第一次尝试:由于
std::forward需要显式模板特化,我最初尝试提供另一组模板重载,但这些重载未被重载决议纳入考虑范围,即便生效也会导致二义性函数调用问题。 - 第二次尝试:尝试特化
std::forward,在尝试阶段就宣告失败。
初始测试代码
我仿写了GCC实现版本的std::forward,仅添加输出语句观测执行流程,代码如下:
namespace test { template<typename T> constexpr T&& fw(typename std::remove_reference<T>::type& t) noexcept { std::cout << "standard" << std::endl; return static_cast<T&&>(t); } template<typename T> constexpr T&& fw(typename std::remove_reference<T>::type&& t) noexcept { std::cout << "standard (r-value)" << std::endl; static_assert ( !std::is_lvalue_reference<T>::value, "template argument substituting T is an lvalue reference type" ); return static_cast<T&&>(t); } }
配套测试代码如下:
class Test { public: template <typename ... T> void test(T&& ... t) { using test::fw; /////////////////////////////////////////////////// ( g(fw<T>(t)), ... ); /////////////////////////////////////////////////// } private: template <typename T> T&& g(T&& t) { std::cout << "g: r-value: " << t << '\n' << std::endl; return std::move(t); } template <typename T> T& g(T& t) { std::cout << "g: l-value " << t << '\n' << std::endl; return t; } }; int main() { int nn = 10; Test t; std::string s("daal"); t.test(12, nn, std::string("alda"), s); return 0; }
当前运行结果与预期
当前代码运行输出如下:
standard g: r-value: 12 standard g: l-value 10 standard g: r-value: alda standard g: l-value daal
预期输出(引用类型标识可选):
standard g: r-value: 12 standard g: l-value 10 specialised (r-value) g: r-value: alda specialised (l-value) g: l-value daal
实现约束
- 必须保留折叠表达式写法,不接受递归模板搭配重载的方案
- 该问题仅出于技术好奇提出,实际业务问题已经通过函数内
if constexpr实现,不存在XY问题
实现方案
不需要额外新增会引发重载决议问题的外层重载,直接在自定义的fw函数内通过if constexpr判断类型即可:针对需要特殊处理的类型(示例中为std::string)走自定义逻辑,其余类型走标准转发逻辑,修改后的fw实现如下:
namespace test { template<typename T> constexpr T&& fw(typename std::remove_reference<T>::type& t) noexcept { using U = std::remove_reference_t<T>; if constexpr (std::is_same_v<U, std::string>) { std::cout << "specialised (l-value)" << std::endl; // 此处编写std::string类型的特殊替换逻辑 } else { std::cout << "standard" << std::endl; } return static_cast<T&&>(t); } template<typename T> constexpr T&& fw(typename std::remove_reference<T>::type&& t) noexcept { static_assert ( !std::is_lvalue_reference<T>::value, "template argument substituting T is an lvalue reference type" ); using U = std::remove_reference_t<T>; if constexpr (std::is_same_v<U, std::string>) { std::cout << "specialised (r-value)" << std::endl; // 此处编写std::string类型的特殊替换逻辑 } else { std::cout << "standard (r-value)" << std::endl; } return static_cast<T&&>(t); } }
该实现完全保留原有折叠表达式的调用写法,不需要修改test函数内的折叠表达式逻辑,编译期即可完成分支判断,无运行时开销,运行后可以得到符合预期的输出。如果需要处理多个特殊类型,直接扩展if constexpr分支即可,也可以通过自定义类型萃取判断是否属于需要特殊处理的类型集合,让逻辑更聚合。
内容的提问来源于stack exchange,提问作者Aconcagua
相关产品推荐
相关产品推荐

