Basically, I want to allow the clients of the class Foo
to define its static constexpr
member variables using arbitrary values based on the template type argument they pass to it when instantiating Foo
.
Here is an MRE:
#include <iostream>
#include <concepts>
template < std::unsigned_integral size_type,
class Allocator = std::allocator<char> >
class Foo
{
public:
static constexpr size_type constant1 { 20 };
static constexpr size_type constant2 { 30 };
void dummy_func( ) const
{
std::cout << constant1 << ' '
<< constant2 << '\n';
}
};
int main( )
{
Foo<std::uint32_t> fooInstance1;
fooInstance1.dummy_func( ); // prints: 20 30
// I want these static members to be initialized
// by the client but this dummy solution does not work
// Foo<std::uint64_t>::constant1 { 120 };
// Foo<std::uint64_t>::constant2 { 130 };
Foo<std::uint64_t> fooInstance2;
fooInstance2.dummy_func( ); // should print: 120 130
}
Note that the values 20 and 30 are for demonstration purposes and don't need to be inside the class since I want to force the client to decide on their own which values they want their version of Foo
to have for its constant1
and constant2
.
I have also taken a look at this similar question but couldn't make it work for the above specific case.
One of the possible approaches that come to my mind is to use variable templates instead. But I'm not sure how. Another one is an explicit instantiation of Foo. Or maybe partial instantiation?
Now I want to mention that the class should obviously be able to go in a header file and then be included in whichever source file that needs to instantiate it and use it.
Is there a simple method to achieve this?
My assumption is Foo class has many static constexpr
variables and writer of Foo class does not like to write long template signature
So I hope to below solution is simple and scalable enough for Foo class writer
template <std::unsigned_integral size_type, size_type... args>
class Foo
{
public:
static constexpr size_type constant1{ std::get<0>(internal_values) };
static constexpr size_type constant2{ std::get<1>(internal_values) };
void dummy_func() const
{
std::cout << constant1 << ' ' << constant2 << std::endl;
}
private:
static constexpr std::tuple<size_type, size_type> internal_values{ std::tuple<decltype(args)...>(std::forward<size_type>(args)...) };
};
and for use of this class you can just write simple code like below
int main()
{
auto fooInstance1 = Foo<std::uint32_t, 20, 30>();
fooInstance1.dummy_func(); // prints: 20 30
auto fooInstance2 = Foo<std::uint64_t, 200, 300>();
fooInstance2.dummy_func(); // prints: 200 300
}