The variadic template constructor of my class cannot modify my class members, why is that so?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I've been working on a task we got by our professor, where I have to work around a variadic template class.
The problem is, I cannot modify the class members within the recursive constructor. I cannot figure out why this is the case, as soon as it goes into the next constructor call, it will discard my changes on the variable.
What I have tried:
using pointer
int* count
instead ofint count
using a setter to set the
counter
I have already googled around for hours, but cannot find a solving answer.
Header file "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";
}
};
main.cpp:
#include "test.h"
int main () {
Counter a {0, 1, 2, 3, 4};
}
The output I got:
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...
c++ c++11 recursion variadic-templates
New contributor
add a comment |
I've been working on a task we got by our professor, where I have to work around a variadic template class.
The problem is, I cannot modify the class members within the recursive constructor. I cannot figure out why this is the case, as soon as it goes into the next constructor call, it will discard my changes on the variable.
What I have tried:
using pointer
int* count
instead ofint count
using a setter to set the
counter
I have already googled around for hours, but cannot find a solving answer.
Header file "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";
}
};
main.cpp:
#include "test.h"
int main () {
Counter a {0, 1, 2, 3, 4};
}
The output I got:
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...
c++ c++11 recursion variadic-templates
New contributor
Perhaps the intention here is forcount
to bestatic
, I'm not certain if that's considered modifying the variable? Either way I imagine your intent is to printtmp
.
– Jonathan Mee
Apr 13 at 14:16
add a comment |
I've been working on a task we got by our professor, where I have to work around a variadic template class.
The problem is, I cannot modify the class members within the recursive constructor. I cannot figure out why this is the case, as soon as it goes into the next constructor call, it will discard my changes on the variable.
What I have tried:
using pointer
int* count
instead ofint count
using a setter to set the
counter
I have already googled around for hours, but cannot find a solving answer.
Header file "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";
}
};
main.cpp:
#include "test.h"
int main () {
Counter a {0, 1, 2, 3, 4};
}
The output I got:
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...
c++ c++11 recursion variadic-templates
New contributor
I've been working on a task we got by our professor, where I have to work around a variadic template class.
The problem is, I cannot modify the class members within the recursive constructor. I cannot figure out why this is the case, as soon as it goes into the next constructor call, it will discard my changes on the variable.
What I have tried:
using pointer
int* count
instead ofint count
using a setter to set the
counter
I have already googled around for hours, but cannot find a solving answer.
Header file "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";
}
};
main.cpp:
#include "test.h"
int main () {
Counter a {0, 1, 2, 3, 4};
}
The output I got:
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...
c++ c++11 recursion variadic-templates
c++ c++11 recursion variadic-templates
New contributor
New contributor
edited Apr 13 at 14:05
TrebledJ
3,98921431
3,98921431
New contributor
asked Apr 13 at 13:06
PrettyCoffeePrettyCoffee
864
864
New contributor
New contributor
Perhaps the intention here is forcount
to bestatic
, I'm not certain if that's considered modifying the variable? Either way I imagine your intent is to printtmp
.
– Jonathan Mee
Apr 13 at 14:16
add a comment |
Perhaps the intention here is forcount
to bestatic
, I'm not certain if that's considered modifying the variable? Either way I imagine your intent is to printtmp
.
– Jonathan Mee
Apr 13 at 14:16
Perhaps the intention here is for
count
to be static
, I'm not certain if that's considered modifying the variable? Either way I imagine your intent is to print tmp
.– Jonathan Mee
Apr 13 at 14:16
Perhaps the intention here is for
count
to be static
, I'm not certain if that's considered modifying the variable? Either way I imagine your intent is to print tmp
.– Jonathan Mee
Apr 13 at 14:16
add a comment |
2 Answers
2
active
oldest
votes
Counter(rest ...);
creates an unnamed temporary object, it does not recursively invoke constructor for this object. Each object is spawned with its own count
therefore you get stream of 1 1 1 1
If you want to delegate object initialization to different constructor then it should be present in member initialization list. This does not seem like a good idea though:
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";
}
add a comment |
As explained by VTT, calling Counter()
inside the body of the constructor create a new Counter()
object.
You can call, recursively, the contructors but you have to do this in the initialization list: look for "delegating contructors" for more informations.
I also would advise you against initialization (and modifications) of member object inside the body of contructors.
If your target is initialize count
with the number of the arguments and tmp
with the value of the last argument, I propose the following ("tag dispatching" based) solution
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"; }
};
You can also avoid tag-dispatching and constructor recursion delegating the recursion about rest...
to a method (maybe static
and also constexpr
, if you want) used to initialize 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"; }
};
Off Topic: to be precise, your Counter
class isn't "a variadic template class".
It's an ordinary (not template) class with one (two, in my first solution) variadic template constructor(s).
-- EDIT --
The OP asks
What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
A static const (maybe also constexpr
) make sense only if the counter is a common value between all the instances of the class.
At the moment doesn't make sense because your Counter
accept initialization lists of different length.
But suppose that number of the argument of the constructor is a template parameter (say N
)... in that case count
is simply N
and can be static constexpr
. You can define a std::array<int, N>
for the values (also a int[N]
but I suggest to avoid to use C-style arrays, when possible, and use std::array
instead) and, making the constructor constexpr
, you can impose the compile time initialization.
The following is a full compiling C++14 example (uses std::make_index_sequence
and std::index_sequence
that, unfortunately, are available only starting from C++14).
Observe that I've defined the f8
variable in main()
as constexpr
: only this way you can impose (pretending there isn't the as-is rule) that f8
is initialized compile-time
#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;
}
If you can use a C++17 enabled compiler, you can also use a deduction guide for foo
template <typename ... Args>
foo(Args...) -> foo<sizeof...(Args)>;
so there is no needs to explicate the template argument defining f8
// .......VVV no more "<8u>"
constexpr foo f3{ 2, 3, 5, 7, 11, 13, 17, 19 };
because it's deduced from the number of the argument of the constructor.
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
@PrettyCoffee - Let me think... Take in count that astatic
variable is a variable common to all instances of the class, so astatic
count
variable (constant, moreover) make sense only if thecount
value is common to all instances ofCounter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.
– max66
Apr 13 at 20:30
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
PrettyCoffee is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55665792%2fthe-variadic-template-constructor-of-my-class-cannot-modify-my-class-members-wh%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Counter(rest ...);
creates an unnamed temporary object, it does not recursively invoke constructor for this object. Each object is spawned with its own count
therefore you get stream of 1 1 1 1
If you want to delegate object initialization to different constructor then it should be present in member initialization list. This does not seem like a good idea though:
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";
}
add a comment |
Counter(rest ...);
creates an unnamed temporary object, it does not recursively invoke constructor for this object. Each object is spawned with its own count
therefore you get stream of 1 1 1 1
If you want to delegate object initialization to different constructor then it should be present in member initialization list. This does not seem like a good idea though:
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";
}
add a comment |
Counter(rest ...);
creates an unnamed temporary object, it does not recursively invoke constructor for this object. Each object is spawned with its own count
therefore you get stream of 1 1 1 1
If you want to delegate object initialization to different constructor then it should be present in member initialization list. This does not seem like a good idea though:
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";
}
Counter(rest ...);
creates an unnamed temporary object, it does not recursively invoke constructor for this object. Each object is spawned with its own count
therefore you get stream of 1 1 1 1
If you want to delegate object initialization to different constructor then it should be present in member initialization list. This does not seem like a good idea though:
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";
}
edited Apr 13 at 13:16
answered Apr 13 at 13:10
VTTVTT
26.4k42550
26.4k42550
add a comment |
add a comment |
As explained by VTT, calling Counter()
inside the body of the constructor create a new Counter()
object.
You can call, recursively, the contructors but you have to do this in the initialization list: look for "delegating contructors" for more informations.
I also would advise you against initialization (and modifications) of member object inside the body of contructors.
If your target is initialize count
with the number of the arguments and tmp
with the value of the last argument, I propose the following ("tag dispatching" based) solution
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"; }
};
You can also avoid tag-dispatching and constructor recursion delegating the recursion about rest...
to a method (maybe static
and also constexpr
, if you want) used to initialize 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"; }
};
Off Topic: to be precise, your Counter
class isn't "a variadic template class".
It's an ordinary (not template) class with one (two, in my first solution) variadic template constructor(s).
-- EDIT --
The OP asks
What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
A static const (maybe also constexpr
) make sense only if the counter is a common value between all the instances of the class.
At the moment doesn't make sense because your Counter
accept initialization lists of different length.
But suppose that number of the argument of the constructor is a template parameter (say N
)... in that case count
is simply N
and can be static constexpr
. You can define a std::array<int, N>
for the values (also a int[N]
but I suggest to avoid to use C-style arrays, when possible, and use std::array
instead) and, making the constructor constexpr
, you can impose the compile time initialization.
The following is a full compiling C++14 example (uses std::make_index_sequence
and std::index_sequence
that, unfortunately, are available only starting from C++14).
Observe that I've defined the f8
variable in main()
as constexpr
: only this way you can impose (pretending there isn't the as-is rule) that f8
is initialized compile-time
#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;
}
If you can use a C++17 enabled compiler, you can also use a deduction guide for foo
template <typename ... Args>
foo(Args...) -> foo<sizeof...(Args)>;
so there is no needs to explicate the template argument defining f8
// .......VVV no more "<8u>"
constexpr foo f3{ 2, 3, 5, 7, 11, 13, 17, 19 };
because it's deduced from the number of the argument of the constructor.
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
@PrettyCoffee - Let me think... Take in count that astatic
variable is a variable common to all instances of the class, so astatic
count
variable (constant, moreover) make sense only if thecount
value is common to all instances ofCounter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.
– max66
Apr 13 at 20:30
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
add a comment |
As explained by VTT, calling Counter()
inside the body of the constructor create a new Counter()
object.
You can call, recursively, the contructors but you have to do this in the initialization list: look for "delegating contructors" for more informations.
I also would advise you against initialization (and modifications) of member object inside the body of contructors.
If your target is initialize count
with the number of the arguments and tmp
with the value of the last argument, I propose the following ("tag dispatching" based) solution
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"; }
};
You can also avoid tag-dispatching and constructor recursion delegating the recursion about rest...
to a method (maybe static
and also constexpr
, if you want) used to initialize 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"; }
};
Off Topic: to be precise, your Counter
class isn't "a variadic template class".
It's an ordinary (not template) class with one (two, in my first solution) variadic template constructor(s).
-- EDIT --
The OP asks
What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
A static const (maybe also constexpr
) make sense only if the counter is a common value between all the instances of the class.
At the moment doesn't make sense because your Counter
accept initialization lists of different length.
But suppose that number of the argument of the constructor is a template parameter (say N
)... in that case count
is simply N
and can be static constexpr
. You can define a std::array<int, N>
for the values (also a int[N]
but I suggest to avoid to use C-style arrays, when possible, and use std::array
instead) and, making the constructor constexpr
, you can impose the compile time initialization.
The following is a full compiling C++14 example (uses std::make_index_sequence
and std::index_sequence
that, unfortunately, are available only starting from C++14).
Observe that I've defined the f8
variable in main()
as constexpr
: only this way you can impose (pretending there isn't the as-is rule) that f8
is initialized compile-time
#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;
}
If you can use a C++17 enabled compiler, you can also use a deduction guide for foo
template <typename ... Args>
foo(Args...) -> foo<sizeof...(Args)>;
so there is no needs to explicate the template argument defining f8
// .......VVV no more "<8u>"
constexpr foo f3{ 2, 3, 5, 7, 11, 13, 17, 19 };
because it's deduced from the number of the argument of the constructor.
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
@PrettyCoffee - Let me think... Take in count that astatic
variable is a variable common to all instances of the class, so astatic
count
variable (constant, moreover) make sense only if thecount
value is common to all instances ofCounter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.
– max66
Apr 13 at 20:30
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
add a comment |
As explained by VTT, calling Counter()
inside the body of the constructor create a new Counter()
object.
You can call, recursively, the contructors but you have to do this in the initialization list: look for "delegating contructors" for more informations.
I also would advise you against initialization (and modifications) of member object inside the body of contructors.
If your target is initialize count
with the number of the arguments and tmp
with the value of the last argument, I propose the following ("tag dispatching" based) solution
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"; }
};
You can also avoid tag-dispatching and constructor recursion delegating the recursion about rest...
to a method (maybe static
and also constexpr
, if you want) used to initialize 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"; }
};
Off Topic: to be precise, your Counter
class isn't "a variadic template class".
It's an ordinary (not template) class with one (two, in my first solution) variadic template constructor(s).
-- EDIT --
The OP asks
What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
A static const (maybe also constexpr
) make sense only if the counter is a common value between all the instances of the class.
At the moment doesn't make sense because your Counter
accept initialization lists of different length.
But suppose that number of the argument of the constructor is a template parameter (say N
)... in that case count
is simply N
and can be static constexpr
. You can define a std::array<int, N>
for the values (also a int[N]
but I suggest to avoid to use C-style arrays, when possible, and use std::array
instead) and, making the constructor constexpr
, you can impose the compile time initialization.
The following is a full compiling C++14 example (uses std::make_index_sequence
and std::index_sequence
that, unfortunately, are available only starting from C++14).
Observe that I've defined the f8
variable in main()
as constexpr
: only this way you can impose (pretending there isn't the as-is rule) that f8
is initialized compile-time
#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;
}
If you can use a C++17 enabled compiler, you can also use a deduction guide for foo
template <typename ... Args>
foo(Args...) -> foo<sizeof...(Args)>;
so there is no needs to explicate the template argument defining f8
// .......VVV no more "<8u>"
constexpr foo f3{ 2, 3, 5, 7, 11, 13, 17, 19 };
because it's deduced from the number of the argument of the constructor.
As explained by VTT, calling Counter()
inside the body of the constructor create a new Counter()
object.
You can call, recursively, the contructors but you have to do this in the initialization list: look for "delegating contructors" for more informations.
I also would advise you against initialization (and modifications) of member object inside the body of contructors.
If your target is initialize count
with the number of the arguments and tmp
with the value of the last argument, I propose the following ("tag dispatching" based) solution
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"; }
};
You can also avoid tag-dispatching and constructor recursion delegating the recursion about rest...
to a method (maybe static
and also constexpr
, if you want) used to initialize 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"; }
};
Off Topic: to be precise, your Counter
class isn't "a variadic template class".
It's an ordinary (not template) class with one (two, in my first solution) variadic template constructor(s).
-- EDIT --
The OP asks
What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
A static const (maybe also constexpr
) make sense only if the counter is a common value between all the instances of the class.
At the moment doesn't make sense because your Counter
accept initialization lists of different length.
But suppose that number of the argument of the constructor is a template parameter (say N
)... in that case count
is simply N
and can be static constexpr
. You can define a std::array<int, N>
for the values (also a int[N]
but I suggest to avoid to use C-style arrays, when possible, and use std::array
instead) and, making the constructor constexpr
, you can impose the compile time initialization.
The following is a full compiling C++14 example (uses std::make_index_sequence
and std::index_sequence
that, unfortunately, are available only starting from C++14).
Observe that I've defined the f8
variable in main()
as constexpr
: only this way you can impose (pretending there isn't the as-is rule) that f8
is initialized compile-time
#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;
}
If you can use a C++17 enabled compiler, you can also use a deduction guide for foo
template <typename ... Args>
foo(Args...) -> foo<sizeof...(Args)>;
so there is no needs to explicate the template argument defining f8
// .......VVV no more "<8u>"
constexpr foo f3{ 2, 3, 5, 7, 11, 13, 17, 19 };
because it's deduced from the number of the argument of the constructor.
edited Apr 13 at 20:55
answered Apr 13 at 13:33
max66max66
39.5k74575
39.5k74575
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
@PrettyCoffee - Let me think... Take in count that astatic
variable is a variable common to all instances of the class, so astatic
count
variable (constant, moreover) make sense only if thecount
value is common to all instances ofCounter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.
– max66
Apr 13 at 20:30
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
add a comment |
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
@PrettyCoffee - Let me think... Take in count that astatic
variable is a variable common to all instances of the class, so astatic
count
variable (constant, moreover) make sense only if thecount
value is common to all instances ofCounter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.
– max66
Apr 13 at 20:30
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
Thank u very much for the hint, that helped a lot! What if I need to get the count as a static const variable and an int array with the length of the counter within compile time and as class members? (Array will be filled with all constructor arguments) Is this within the C++ possibilitys?
– PrettyCoffee
Apr 13 at 19:03
@PrettyCoffee - Let me think... Take in count that a
static
variable is a variable common to all instances of the class, so a static
count
variable (constant, moreover) make sense only if the count
value is common to all instances of Counter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.– max66
Apr 13 at 20:30
@PrettyCoffee - Let me think... Take in count that a
static
variable is a variable common to all instances of the class, so a static
count
variable (constant, moreover) make sense only if the count
value is common to all instances of Counter
. At the moment do not make sense because you can call the constructor of different instances with different number of arguments. It's different if the number of the template argument is a template parameter of the class. Give me some minutes and I prepare an example of what I mean.– max66
Apr 13 at 20:30
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
@PrettyCoffee - answer improved; hope this helps.
– max66
Apr 13 at 20:55
add a comment |
PrettyCoffee is a new contributor. Be nice, and check out our Code of Conduct.
PrettyCoffee is a new contributor. Be nice, and check out our Code of Conduct.
PrettyCoffee is a new contributor. Be nice, and check out our Code of Conduct.
PrettyCoffee is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55665792%2fthe-variadic-template-constructor-of-my-class-cannot-modify-my-class-members-wh%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Perhaps the intention here is for
count
to bestatic
, I'm not certain if that's considered modifying the variable? Either way I imagine your intent is to printtmp
.– Jonathan Mee
Apr 13 at 14:16