推断大多数模板对象的参数,但在调用模板函数时对其他对象显式

Inferring parameter of most template objects, but being explicit with others when calling a template function?

本文关键字:对象 函数 其他 调用 大多数 参数      更新时间:2023-10-16

我注意到,当传递给函数时,现代C++(C++11等(有时可以推断模板对象的int模板参数,而无需使用大括号显式传递int值。

但是,如果我想要一个函数参数:

bitset<N_OLD>

int模板参数自动推断为函数输入,函数返回值:

bitset<N_NEW>

在使用大括号或大小写调用函数时明确指定。这可能吗?示例:

#include <bitset>
using namespace std;
// expand or truncate bitset without sign extension
template<int N_NEW, int N_OLD> 
bitset<N_NEW>
bresize(const bitset<N_OLD> value)
{
return bitset<N_NEW> {value.to_ullong() & ((1<<N_NEW)-1) }; 
}

例如:

bitset<16> x {0xABCD};
// version explicit everything (Not what I want)
auto y2 = bresize<32, 16>(x); 
//Inference Attempt #1
auto  y1 = bresize<32>(x); 
//Inference Attempt #2
bitset<32> y3 = bresize(x);
//Inference Attempt #3
auto y4 = (bitset<32>)bresize(x);

我只是想了解在上述场景中推断模板大小参数时的规则是什么。目标是尽可能多地推断bitset的输入大小,但要明确输出大小。这在C++11中可能吗?

我将给出一个通用答案,然后向您展示如何将其应用于您的案例。

不能仅从返回类型推导模板参数。

示例1

template <class T, class R>
auto foo(T) -> R;

CCD_ 5可以,而不能。因此,在调用foo时,您需要始终保持明确。

由于R在模板参数中位于T之后,这意味着在指定R时也需要指定T,即使T是可扣除的,例如foo<int, double>(24)

解决方案非常简单:将不可推导的模板参数放在第一位:

template <class R, class T>
auto bar(T) -> R;

你可以这样称呼它:

bar<double>(24); // R explicit to double, T deduced as int from the parameters

示例2

template <class T, class U>
auto foo(T, U) -> U

这里可以推导出CCD_ 13,因为它可以从参数中推导出来。

示例3

如果不可扣除模板参数依赖于另一个可扣除模板的参数,则您可以根据可扣除参数计算

template <class T>
auto foo(T) -> std::decay_t<T>

您的案例

首先,std::bitset的模板参数类型是std::size_t,而不是int。仅此一项就将导致扣除问题。先解决这个问题。

接下来要确保的是首先要有不可扣除的模板参数:

template<std::size_t N_NEW, std::size_t N_OLD> 
std::bitset<N_NEW>
bresize(std::bitset<N_OLD> value) { /* ... */ }

然后您可以调用bresize作为:

bresize<32>(x);

此外,如果N_NEW可以是根据N_OLD计算的constexpr,那么您可以完全跳过显式参数:

template<std::size_t N_OLD> 
std::bitset<N_OLD * 2>
bresize(std::bitset<N_OLD> value) { /* ... */ }

template<std::size_t N_OLD, std::size_t N_NEW = N_OLD * 2> 
std::bitset<N_NEW>
bresize(std::bitset<N_OLD> value) { /* ... */ }

constexpr auto new_width(std::size_t old_width) => std::size_t
{
return old_width * 2;
/* or any constexpr allowed body */
};
template<std::size_t N_OLD> 
std::bitset<new_width(N_OLD)>
bresize(std::bitset<N_OLD> value) { /* ... */ }

template<std::size_t N_OLD, std::size_t N_NEW = new_width(N_OLD)> 
std::bitset<N_NEW>
bresize(std::bitset<N_OLD> value) { /* ... */ }

一些小的离题挑剔:const T作为一个参数没有多大意义。使用const T&T