C++ 静态变量的参数包扩展
我在考虑以下问题: 让我们用以下方式定义合并数组的合并函数:C++ 静态变量的参数包扩展,c++,templates,variadic-templates,C++,Templates,Variadic Templates,我在考虑以下问题: 让我们用以下方式定义合并数组的合并函数: // input is (const void*, size_t, const void*, size_t,...) template<typename...ARGS> MyArray Concatenation(ARGS...args) 我想有一个方法: template<typename...ARGS> MyArray AutoConcatenation(); 只是给顾问的信息。我正在寻找自动关联方法
// input is (const void*, size_t, const void*, size_t,...)
template<typename...ARGS>
MyArray Concatenation(ARGS...args)
我想有一个方法:
template<typename...ARGS>
MyArray AutoConcatenation();
只是给顾问的信息。我正在寻找自动关联方法的实现,不是为了重新声明,也不是为了重新声明以前的代码,谢谢。以下是可能的解决方案:
enum Delimiters { Delimiter };
const void* findData(size_t count) { return nullptr; }
template<typename...ARGS>
const void* findData(size_t count, size_t, ARGS...args)
{
return findData(count, args...);
}
template<typename...ARGS>
const void* findData(size_t count, const void* data, ARGS...args)
{
return count ? findData(count - 1, args...) : data;
}
template<typename...ARGS>
MyArray reordered(size_t count, Delimiters, ARGS...args)
{
return Concatenate(args...);
}
template<typename...ARGS>
MyArray reordered(size_t count, const void* size, ARGS...args)
{
return reordered(count, args...);
}
template<typename...ARGS>
MyArray reordered(size_t count, size_t size, ARGS...args)
{
return reordered(count + 1, args..., findData(count, args...), size);
}
template<typename...ARGS>
MyArray AutoConcatenate()
{
return reordered(0, ARGS::LAYOUT_SIZE..., ARGS::LAYOUT..., Delimiter);
}
#include <cstddef>
#include <tuple>
#include <utility>
#include <iostream>
#include <typeinfo>
#include <type_traits>
struct MyArray { };
template<class... ARGS> MyArray Concatenation(ARGS... args)
{
// Just some dummy code for testing.
using arr = int[];
(void)arr{(std::cout << typeid(args).name() << ' ' << args << '\n' , 0)...};
return {};
}
struct A { static void* DATA; static std::size_t SIZE; };
struct B { static void* DATA; static std::size_t SIZE; };
struct C { static void* DATA; static std::size_t SIZE; };
// Also needed for testing.
void* A::DATA;
std::size_t A::SIZE;
void* B::DATA;
std::size_t B::SIZE;
void* C::DATA;
std::size_t C::SIZE;
// The useful stuff starts here.
template<class T, std::size_t... Is> MyArray concat_hlp_2(const T& tup, std::index_sequence<Is...>)
{
return Concatenation(std::get<Is>(tup)...);
}
template<class T> MyArray concat_hlp_1(const T& tup)
{
return concat_hlp_2(tup, std::make_index_sequence<std::tuple_size<T>::value>{});
}
template<class... ARGS> MyArray AutoConcatenation()
{
return concat_hlp_1(std::tuple_cat(std::make_tuple(ARGS::DATA, ARGS::SIZE)...));
}
int main()
{
AutoConcatenation<A, B, C>();
}
enum分隔符{Delimiter};
const void*findData(大小计数){return nullptr;}
模板
常量void*findData(大小计数、大小、参数…参数)
{
返回findData(计数、参数…);
}
模板
常量无效*findData(大小计数、常量无效*数据、参数…参数)
{
返回计数?findData(计数-1,参数…):数据;
}
模板
MyArray已重新排序(大小\u t计数、分隔符、参数…参数)
{
返回连接(args…);
}
模板
MyArray已重新排序(大小\u t计数、常量无效*大小、参数…参数)
{
返回重新排序(计数、参数…);
}
模板
MyArray已重新排序(大小\u t计数、大小\u t大小、参数…参数)
{
返回重新排序(计数+1,参数…,findData(计数,参数…,大小);
}
模板
MyArray AutoConcatenate()
{
返回重新排序(0,ARGS::LAYOUT\u SIZE…,ARGS::LAYOUT…,分隔符);
}
如果您知道更优雅的方式,请告诉我。
编辑
一种更优雅的方法是将函数参数计数作为模板参数…我认为下面的方法更优雅,它演示了常见的递归解包模式。最后,它不执行任何带有内存布局的伏都教,并且尝试对C++泛型编程进行惯用。p>
#include <iostream>
#include <string>
using namespace std;
// Handle zero arguments.
template <typename T = string>
T concat_helper() { return T(); }
// Handle one pair.
template <typename T = string>
T concat_helper(const T &first, size_t flen) { return first; }
// Handle two or more pairs. Demonstrates the recursive unpacking pattern
// (very common with variadic arguments).
template <typename T = string, typename ...ARGS>
T concat_helper(const T &first, size_t flen,
const T &second, size_t slen,
ARGS ... rest) {
// Your concatenation code goes here. We're assuming we're
// working with std::string, or anything that has method length() and
// substr(), with obvious behavior, and supports the + operator.
T concatenated = first.substr(0, flen) + second.substr(0, slen);
return concat_helper<T>(concatenated, concatenated.length(), rest...);
}
template <typename T, typename ...ARGS>
T Concatenate(ARGS...args) { return concat_helper<T>(args...); }
template <typename T>
struct pack {
T data;
size_t dlen;
};
template <typename T>
T AutoConcatenate_helper() { return T(); }
template <typename T>
T AutoConcatenate_helper(const pack<T> *packet) {
return packet->data;
}
template <typename T, typename ...ARGS>
T AutoConcatenate_helper(const pack<T> *first, const pack<T> *second,
ARGS...rest) {
T concatenated = Concatenate<T>(first->data, first->dlen,
second->data, second->dlen);
pack<T> newPack;
newPack.data = concatenated;
newPack.dlen = concatenated.length();
return AutoConcatenate_helper<T>(&newPack, rest...);
}
template <typename T, typename ...ARGS>
T AutoConcatenate(ARGS...args) {
return AutoConcatenate_helper<T>(args...);
}
int main() {
pack<string> first;
pack<string> second;
pack<string> third;
pack<string> last;
first.data = "Hello";
first.dlen = first.data.length();
second.data = ", ";
second.dlen = second.data.length();
third.data = "World";
third.dlen = third.data.length();
last.data = "!";
last.dlen = last.data.length();
cout << AutoConcatenate<string>(&first, &second, &third, &last) << endl;
return 0;
}
#包括
#包括
使用名称空间std;
//处理零参数。
模板
T concat_helper(){return T();}
//处理一对。
模板
T concat_helper(const T&first,size_T flen){return first;}
//处理两对或更多对。演示递归解包模式
//(非常常见于可变参数)。
模板
混凝土辅助材料(先施工后尺寸),
const T&second,尺寸,
ARGS…rest){
//你的连接码在这里,我们假设
//使用std::string或任何具有方法length()和
//substr(),具有明显的行为,并支持+运算符。
连接的T=first.substr(0,flen)+second.substr(0,slen);
返回concat_helper(连接的,连接的.length(),rest…);
}
模板
T连接(ARGS…ARGS){返回concat_helper(ARGS…;}
模板
结构包{
T数据;
大小;
};
模板
T AutoConcatenate_helper(){return T();}
模板
自动连接辅助程序(常数包*数据包){
返回数据包->数据;
}
模板
自动连接辅助对象(常量块*第一,常量块*第二,
ARGS…rest){
T concatenated=连接(第一个->数据,第一个->数据线,
第二->数据,第二->数据线);
新包装;
newPack.data=已连接;
newPack.dlen=concatenated.length();
返回AutoConcatenate\u帮助程序(&newPack,rest…);
}
模板
自动关联(ARGS…ARGS){
返回自动关联辅助对象(args…);
}
int main(){
先打包;
第二包;
第三组;
最后打包;
first.data=“你好”;
first.dlen=first.data.length();
第二,data=“,”;
second.dlen=second.data.length();
第三,数据=“世界”;
third.dlen=third.data.length();
last.data=“!”;
last.dlen=last.data.length();
不能使用std::tuple
的惰性解决方案:
- 为参数包的每个元素创建一个
数据
和大小
的元组
- 使用
std::tuple\u cat
将元组列表展平为一个大元组
- 通过展开
std::index_序列中的索引列表,将生成的元组元素应用于串联
在以下代码中,测试线束比实际解决方案长:
enum Delimiters { Delimiter };
const void* findData(size_t count) { return nullptr; }
template<typename...ARGS>
const void* findData(size_t count, size_t, ARGS...args)
{
return findData(count, args...);
}
template<typename...ARGS>
const void* findData(size_t count, const void* data, ARGS...args)
{
return count ? findData(count - 1, args...) : data;
}
template<typename...ARGS>
MyArray reordered(size_t count, Delimiters, ARGS...args)
{
return Concatenate(args...);
}
template<typename...ARGS>
MyArray reordered(size_t count, const void* size, ARGS...args)
{
return reordered(count, args...);
}
template<typename...ARGS>
MyArray reordered(size_t count, size_t size, ARGS...args)
{
return reordered(count + 1, args..., findData(count, args...), size);
}
template<typename...ARGS>
MyArray AutoConcatenate()
{
return reordered(0, ARGS::LAYOUT_SIZE..., ARGS::LAYOUT..., Delimiter);
}
#include <cstddef>
#include <tuple>
#include <utility>
#include <iostream>
#include <typeinfo>
#include <type_traits>
struct MyArray { };
template<class... ARGS> MyArray Concatenation(ARGS... args)
{
// Just some dummy code for testing.
using arr = int[];
(void)arr{(std::cout << typeid(args).name() << ' ' << args << '\n' , 0)...};
return {};
}
struct A { static void* DATA; static std::size_t SIZE; };
struct B { static void* DATA; static std::size_t SIZE; };
struct C { static void* DATA; static std::size_t SIZE; };
// Also needed for testing.
void* A::DATA;
std::size_t A::SIZE;
void* B::DATA;
std::size_t B::SIZE;
void* C::DATA;
std::size_t C::SIZE;
// The useful stuff starts here.
template<class T, std::size_t... Is> MyArray concat_hlp_2(const T& tup, std::index_sequence<Is...>)
{
return Concatenation(std::get<Is>(tup)...);
}
template<class T> MyArray concat_hlp_1(const T& tup)
{
return concat_hlp_2(tup, std::make_index_sequence<std::tuple_size<T>::value>{});
}
template<class... ARGS> MyArray AutoConcatenation()
{
return concat_hlp_1(std::tuple_cat(std::make_tuple(ARGS::DATA, ARGS::SIZE)...));
}
int main()
{
AutoConcatenation<A, B, C>();
}
同样,索引序列的大小是原始参数包的两倍,但是我们构建了数据
和大小
的单独数组,然后根据当前索引的奇偶性使用标记调度从一个或另一个中选择元素
这看起来可能不像前面的代码那么好,但它不涉及任何模板递归(据我所知,在现代编译器中使用编译器内部函数实现了std::make_index_sequence
),并减少了模板实例化的数量,因此编译速度应该更快
通过使用指向静态成员的指针数组,可以创建
select
助手constepr
,但实际上这是不必要的。我已经测试了MSVC 2015 U2、Clang 3.8.0和GCC 6.1.0,它们都优化了这一点,可以直接调用串联
(就像基于元组的解决方案一样).连接是什么意思?这无关紧要。解决方案独立于函数的语义。请注意,如果数据是c字符串,A::DATA=“abc”,A::SIZE=3,连接(A::DATA,A::SIZE,A::DATA,A::SIZE)将是带有数据“abcabc”的数组一般来说,回答你自己的问题是不习惯的。也许你应该把这个添加到你原来的帖子中,然后改变你的帖子,要求一个更优雅的解决方案。@William问你自己的问题没有错。@Zerges,当然。回答这个问题怎么样?特别是不给它一天时间?此外,我不记得cal了请注意,“错误”。注意,您需要对该代码进行一些小的更改,使之符合标准(我想您已经使用Visual C++测试了它,但仍然没有实现两阶段查找):您需要向前声明“代码>模板模板Vult*FIDDATA(SiZext计数,const Value*数据,ARGS…ARGS)。和模板MyArray重新排序(大小\u t计数、大小\u t大小、参数…参数);
。要查看漂亮的错误消息,可以尝试编译
#include <iostream>
#include <string>
using namespace std;
// Handle zero arguments.
template <typename T = string>
T concat_helper() { return T(); }
// Handle one pair.
template <typename T = string>
T concat_helper(const T &first, size_t flen) { return first; }
// Handle two or more pairs. Demonstrates the recursive unpacking pattern
// (very common with variadic arguments).
template <typename T = string, typename ...ARGS>
T concat_helper(const T &first, size_t flen,
const T &second, size_t slen,
ARGS ... rest) {
// Your concatenation code goes here. We're assuming we're
// working with std::string, or anything that has method length() and
// substr(), with obvious behavior, and supports the + operator.
T concatenated = first.substr(0, flen) + second.substr(0, slen);
return concat_helper<T>(concatenated, concatenated.length(), rest...);
}
template <typename T, typename ...ARGS>
T Concatenate(ARGS...args) { return concat_helper<T>(args...); }
template <typename T>
struct pack {
T data;
size_t dlen;
};
template <typename T>
T AutoConcatenate_helper() { return T(); }
template <typename T>
T AutoConcatenate_helper(const pack<T> *packet) {
return packet->data;
}
template <typename T, typename ...ARGS>
T AutoConcatenate_helper(const pack<T> *first, const pack<T> *second,
ARGS...rest) {
T concatenated = Concatenate<T>(first->data, first->dlen,
second->data, second->dlen);
pack<T> newPack;
newPack.data = concatenated;
newPack.dlen = concatenated.length();
return AutoConcatenate_helper<T>(&newPack, rest...);
}
template <typename T, typename ...ARGS>
T AutoConcatenate(ARGS...args) {
return AutoConcatenate_helper<T>(args...);
}
int main() {
pack<string> first;
pack<string> second;
pack<string> third;
pack<string> last;
first.data = "Hello";
first.dlen = first.data.length();
second.data = ", ";
second.dlen = second.data.length();
third.data = "World";
third.dlen = third.data.length();
last.data = "!";
last.dlen = last.data.length();
cout << AutoConcatenate<string>(&first, &second, &third, &last) << endl;
return 0;
}
#include <cstddef>
#include <tuple>
#include <utility>
#include <iostream>
#include <typeinfo>
#include <type_traits>
struct MyArray { };
template<class... ARGS> MyArray Concatenation(ARGS... args)
{
// Just some dummy code for testing.
using arr = int[];
(void)arr{(std::cout << typeid(args).name() << ' ' << args << '\n' , 0)...};
return {};
}
struct A { static void* DATA; static std::size_t SIZE; };
struct B { static void* DATA; static std::size_t SIZE; };
struct C { static void* DATA; static std::size_t SIZE; };
// Also needed for testing.
void* A::DATA;
std::size_t A::SIZE;
void* B::DATA;
std::size_t B::SIZE;
void* C::DATA;
std::size_t C::SIZE;
// The useful stuff starts here.
template<class T, std::size_t... Is> MyArray concat_hlp_2(const T& tup, std::index_sequence<Is...>)
{
return Concatenation(std::get<Is>(tup)...);
}
template<class T> MyArray concat_hlp_1(const T& tup)
{
return concat_hlp_2(tup, std::make_index_sequence<std::tuple_size<T>::value>{});
}
template<class... ARGS> MyArray AutoConcatenation()
{
return concat_hlp_1(std::tuple_cat(std::make_tuple(ARGS::DATA, ARGS::SIZE)...));
}
int main()
{
AutoConcatenation<A, B, C>();
}
template<std::size_t Size> const void* select(std::false_type, std::size_t idx,
const void* (& arr_data)[Size], std::size_t (&)[Size])
{
return arr_data[idx];
}
template<std::size_t Size> std::size_t select(std::true_type, std::size_t idx,
const void* (&)[Size], std::size_t (& arr_size)[Size])
{
return arr_size[idx];
}
template<std::size_t... Is> MyArray concat_hlp(std::index_sequence<Is...>,
const void* (&& arr_data)[sizeof...(Is) / 2], std::size_t (&& arr_size)[sizeof...(Is) / 2])
{
return Concatenation(select(std::bool_constant<Is % 2>{}, Is / 2, arr_data, arr_size)...);
}
template<class... ARGS> MyArray AutoConcatenation()
{
return concat_hlp(std::make_index_sequence<sizeof...(ARGS) * 2>{}, {ARGS::DATA...}, {ARGS::SIZE...});
}