如何将类型推导与函数参数声明分开?

问题描述 投票:0回答:1

如果我的函数

foo
按值而不是通用(转发)引用接受原始类型,我的应用程序会显着加速。但是,如果非基本类型不通过通用引用传递,则加速会丢失。如果
foo
接受固定数量的参数,这就能解决问题:

#include <cstdio>
#include <string>
#include <type_traits>

template <typename T>
requires (!std::is_scalar_v<T>)
auto foo(T&&){
    std::puts("pass by universal reference");
}

template <typename T>
requires std::is_scalar_v<T>
auto foo(T){
    std::puts("pass by value");
}

int main(){
    foo(42);  // pass by value
    foo(std::string{"hello"}); // pass by universal reference
    
    return 0;
}

但是,问题是

foo
接受模板参数包,并且某些参数可能是原语,而其他参数可能不是。因此,
foo
必须首先推导参数类型,然后,如果它们不是基元,则将它们转换为通用引用。如果
foo
是类模板,则可以使用演绎指南来实现:

#include <cstdio>
#include <string>
#include <type_traits>

template <typename T>
using MaybeRef = std::conditional_t<std::is_scalar_v<T>, T, T&&>;

#include <tuple>
template <typename... Ts>
struct Foo {
    
    Foo(MaybeRef<Ts>... args) {
        static_assert(std::is_same_v<std::tuple_element_t<0, std::tuple<MaybeRef<Ts>...>>, int>);
        static_assert(std::is_same_v<std::tuple_element_t<1, std::tuple<MaybeRef<Ts>...>>, std::string&>);
        std::puts("passed");
    }
};

template <typename... Ts>
Foo(Ts&&...) -> Foo<MaybeRef<Ts>...>;

int main(){
    std::string str = "hello";
    Foo{42, str};

    return 0;
}

但是,我不知道如何为我的功能实现相同的功能

foo
。 这可能吗?如何实现?

c++ variadic-templates template-meta-programming type-deduction forwarding-reference
1个回答
0
投票

在当前的 C++ 中不可能做到这一点,但有一些相关的建议:

  • Herb Sutter 未发布的 D0708 建议(除其他外)添加
    in
    关键字,这将告诉编译器将参数声明为按值或按引用,具体取决于哪种更有效。
  • Gašper Ažman 等人。在一篇尚未发表的论文D1107中提出了一种更通用的机制,称为计算推导,它基本上完全符合你的要求:“将类型推导与函数参数声明分开”。
  • 最近,James Touton 的P2998,它允许在库中实现您想要的功能,因为它会在调用函数模板时发挥推导指南的作用。
© www.soinside.com 2019 - 2024. All rights reserved.