Pre*_*fee 20 c++ recursion variadic-templates c++11
我一直在从事教授所完成的任务,在该任务中,我必须解决可变参数模板类。问题是,我无法在递归构造函数中修改类成员。我不知道为什么会这样,一旦进入下一个构造函数调用,它将丢弃我对变量的更改。
我尝试过的
使用指针int* count代替int count
使用设置器来设置 counter
我已经在Google搜寻了几个小时,但找不到解决方法。
头文件“ test.h”:
#include <cstdarg>
#include <iostream>
class Counter {
private:
int count = 0;
int tmp;
public:
template <typename... Rest> Counter (int t, Rest... rest) {
count++;
std::cout << "start recursive number " << count << "...\n";
Counter(rest ...);
tmp = t;
std::cout << "end recursive number " << count << "...\n";
}
Counter (int t) {
count++;
tmp = t;
std::cout << "reached end of recursive -> " << count << "\n";
}
};
Run Code Online (Sandbox Code Playgroud)
main.cpp:
#include "test.h"
int main () {
Counter a {0, 1, 2, 3, 4};
}
Run Code Online (Sandbox Code Playgroud)
我得到的输出:
start recursive number 1...
start recursive number 1...
start recursive number 1...
start recursive number 1...
reached end of recursive -> 1
end recursive number 1...
end recursive number 1...
end recursive number 1...
end recursive number 1...
Run Code Online (Sandbox Code Playgroud)
use*_*670 24
Counter(rest ...);创建一个未命名的临时对象,它不会递归调用此对象的构造函数。每个对象都有自己的生成,count因此您得到1 1 1 1的流
如果要将对象初始化委托给其他构造函数,则它应该出现在成员初始化列表中。但是,这似乎不是一个好主意:
template <typename... Rest> Counter (int t, Rest... rest)
: Counter{rest...}
{
count++;
std::cout << "start recursive number " << count << "...\n";
tmp = t;
std::cout << "end recursive number " << count << "...\n";
}
Run Code Online (Sandbox Code Playgroud)
max*_*x66 12
如VTT Counter()所述,在构造函数的主体内部调用会创建一个新Counter()对象。
您可以递归地调用构造函数,但是您必须在初始化列表中执行此操作:查找“代理构造函数”以获取更多信息。
我也建议您不要在构造函数体内初始化(和修改)成员对象。
如果您的目标是count使用参数的数量和tmp最后一个参数的值进行初始化的,那么我提出以下(基于“标签分发”的)解决方案
class Counter
{
private:
struct tag
{ };
int count = 0;
int tmp;
Counter (tag tg, std::size_t c0, int t) : count(c0), tmp{t}
{ std::cout << "end: " << tmp << ", " <<count << "\n"; }
template <typename... Rest>
Counter (tag t0, std::size_t c0, int t, Rest... rest)
: Counter{t0, c0, rest...}
{ std::cout << "recursion: " << tmp << ", " << count << "\n"; }
public:
template <typename... Rest>
Counter (Rest... rest) : Counter{tag{}, sizeof...(Rest), rest...}
{ std::cout << "start: " << tmp << ", " << count << "\n"; }
};
Run Code Online (Sandbox Code Playgroud)
您还可以避免使用标记分派和构造函数递归将递归委派rest...给用于初始化的方法(如果需要static,也可以constexpr,如果需要的话)tmp
class Counter
{
private:
int count = 0;
int tmp;
static int getLastInt (int i)
{ return i; }
template <typename ... Rest>
static int getLastInt (int, Rest ... rs)
{ return getLastInt(rs...); }
public:
template <typename... Rest>
Counter (Rest... rest)
: count(sizeof...(Rest)), tmp{getLastInt(rest...)}
{ std::cout << tmp << ", " << count << "\n"; }
};
Run Code Online (Sandbox Code Playgroud)
主题外:确切地说,您的Counter课程不是“可变参数模板课程”。
这是一个普通的(不是模板)类,具有一个(两个,在我的第一个解决方案中)可变参数模板构造函数。
-编辑-
OP问
如果我需要将计数作为静态const变量和int数组(计数器的长度在编译时间内以及作为类成员)获得,该怎么办?(数组将使用所有构造函数参数填充)这是否在C ++的可能性之内?
constexpr仅当计数器是该类的所有实例之间的公共值时,静态const(也许也才有意义)才有意义。
目前没有任何意义,因为您Counter接受不同长度的初始化列表。
但是,假设构造函数的参数编号是一个模板参数(例如N)……在这种情况下count很简单N并且可以是static constexpr。您可以std::array<int, N>为这些值定义a (也可以是a,int[N]但我建议尽量避免使用C样式的数组,std::array而应改用),并使用构造函数constexpr可以强制进行编译时初始化。
以下是一个完整的C ++ 14编译示例(使用std::make_index_sequence和std::index_sequence不幸的是,这些用法仅从C ++ 14开始可用)。
观察到我已将f8变量定义main()为constexpr:只有这样,您才能强加(假装没有按原样的规则)f8已初始化的编译时
#include <array>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t>
using getType = T;
template <std::size_t N, typename = std::make_index_sequence<N>>
struct foo;
template <std::size_t N, std::size_t ... Is>
struct foo<N, std::index_sequence<Is...>>
{
static_assert( sizeof...(Is), "!" );
static constexpr auto count = N;
const std::array<int, N> arr;
constexpr foo (getType<int, Is> ... is) : arr {{ is ... }}
{ }
};
int main ()
{
constexpr foo<8u> f8 { 2, 3, 5, 7, 11, 13, 17, 19 };
for ( auto const & i : f8.arr )
std::cout << i << ' ';
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果可以使用启用了C ++ 17的编译器,还可以使用推导指南 foo
template <typename ... Args>
foo(Args...) -> foo<sizeof...(Args)>;
Run Code Online (Sandbox Code Playgroud)
因此无需重复定义模板参数 f8
// .......VVV no more "<8u>"
constexpr foo f3{ 2, 3, 5, 7, 11, 13, 17, 19 };
Run Code Online (Sandbox Code Playgroud)
因为它是根据构造函数的参数编号推导出来的。
| 归档时间: |
|
| 查看次数: |
660 次 |
| 最近记录: |