C++ 完美的正向返回类型,但带有常数

C++ 完美的正向返回类型,但带有常数,c++,C++,我想完美地转发对函数的调用,但我总是想返回返回类型的const版本。我的意思是,当返回引用时,我想要一个常量&。我怎样才能做到这一点 我不关心非引用类型。毕竟,返回常量T(不带引用)与T没有太大区别 我只关心顶层的const。如果T是指针类型或其他更复杂的类型,我不想在更深的地方添加常量 如果我只是正常转接电话: template<class Func, class... Args> decltype(auto) Example(Func f, Args&&...

我想完美地转发对函数的调用,但我总是想返回返回类型的
const
版本。我的意思是,当返回引用时,我想要一个
常量&
。我怎样才能做到这一点

  • 我不关心非引用类型。毕竟,返回常量T(不带引用)与
    T
    没有太大区别
  • 我只关心顶层的
    const
    。如果
    T
    是指针类型或其他更复杂的类型,我不想在更深的地方添加常量
如果我只是正常转接电话:

template<class Func, class... Args>
decltype(auto) Example(Func f, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}
模板
decltype(自动)示例(函数f、参数&&…参数)
{ 
返回乐趣(std::forward(args)…);
}
f
恰好返回,比如说,
int&
然后我只得到:
int&
。但是我想得到一个
常量int&


decltype(auto)const
decltype(auto-const)
似乎是非法的。

这里有一个可能的解决方案。引用被转换为
常量&
。任何其他类型保持不变。不过,我想听听第二种观点,如果我没有考虑过一些拐角的情况。
#include <utility>

template<typename T>
struct add_const_to_ref {
        using type = T;
};

template<typename T>
struct add_const_to_ref<T&> {
        using type = const T&;
};

template<typename T>
using add_const_to_ref_t = typename add_const_to_ref<T>::type;

template<class Func, class... Args>
add_const_to_ref_t<decltype(std::declval<Func>()(std::forward<Args>(std::declval<Args&&>())...))> ConstInvoke(Func f, Args&&... args)
{
            return f(std::forward<Args>(args)...);
}

Blueprint:使用decltype和declval来计算
f
返回的内容。使用一个简单的助手类来指定返回类型。结束。对于您尝试的解决方案,请注意,如果
auto
解析为
int&
,那么将
const
添加到
auto
将得到
int&const
,而不是
const int&
@SamVarshavchik,我一定会尝试!然而,在阅读了这样的答案之后,我发现用
decltype(auto)
替换
decltype(expr)
在我的脑海中非常不稳定(如果有一个我不知道的情况呢?),返回
const
值有什么意义呢?我的意思是,我知道它可以防止意外的临时任务分配(就像内置的情况一样),但是这值得吗?你想解决一些实际问题吗?是的,那更好。但它仍然缺少一点:当fun()返回
int
时会发生什么?我假设Example()也应该返回
int
?那么
int*
int**
呢?您可以用
std::invoke\u result
替换
decltype(std::declval()(std::forward(std::declval())…)
,使其更具可读性。
#include <iostream>

int& foo(int& x) {
        return x;
}

int bar() {
        return 5;
}
int main() {
        int x = 0;
        std::cout << std::is_same_v<int&, decltype(ConstInvoke(foo, x))> << "\n";
        std::cout << std::is_same_v<int, decltype(ConstInvoke(foo, x))> << "\n";
        std::cout << std::is_same_v<const int&, decltype(ConstInvoke(foo, x))> << "\n";

        std::cout << std::is_same_v<int&, decltype(ConstInvoke(bar))> << "\n";
        std::cout << std::is_same_v<int, decltype(ConstInvoke(bar))> << "\n";
        std::cout << std::is_same_v<const int&, decltype(ConstInvoke(bar))> << "\n";
};
template<typename T>
decltype(auto) as_const_to_ref(T&& arg) {
        return (add_const_to_ref_t<T>)(std::forward<T>(arg));
}

template<class Func, class... Args>
decltype(auto) ConstInvoke2(Func f, Args&&... args)
{
            return as_const_to_ref(f(std::forward<Args>(args)...));
}