C++ (Somehow) limit struct to parent union size - c++

I'm attempting to create a color class of variable size- given a template-determined array of values, I'd like to create named aliases of each value in the array, ie:
template<int C = 3, typename T = unsigned char>
class Color {
public:
union {
T v[C];
struct {
T r, g, b, a;
};
};
};
However, if I try to use the same class for C=3, the union mandates a size of 4 bytes (the 'a' member). Alternatively, using a mathematically expressed bitfield size for a (struct named a, anonymous T member, size evaluates to 1 at C>3), the compiler issues a permissive warning (non-suppressible, as per In gcc, how to mute the -fpermissive warning? ), something unsuitable for a larger-scale API.
How would I go about allowing a single class to handle different numbers of variables, while retaining per-variable names and without implementing recursive-include macro magic (tried this, shouldn't have). Thanks in advance!
Edit: To clarify the question, an answer to any of the following will solve this problem:
Suppress GCC's -fpermissive errors (#pragma diagnostic ignored doesn't work for permissive)
Set maximum size of union or child struct not to exceed C bytes
Allow bitfield length of 0 for members not covered by C bytes (GCC allows mathematical expressions for bitfield length, such as (C-3 > 0)?8:0; )
Disable members not covered by C bytes by some other means (ie, mythical static_if() )

You could make a specialization of the struct for different cases of C:
template <int C = 3, typename T = unsigned char> union Color;
template <typename T>
union Color<3,T> {
T v[3];
struct {
T r,g,b;
};
};
template <typename T>
union Color<4,T> {
T v[4];
struct {
T r,g,b,a;
};
};
Note that anonymous structs are non-standard.
If using member functions is a possibility, I think that would be a better way to go:
template <int C,typename T>
class Color {
public:
using Values = T[C];
Values &v() { return v_; }
const Values &v() const { return v_; }
T& r() { return v_[0]; }
T& g() { return v_[1]; }
T& b() { return v_[2]; }
template <int C2 = C,
typename = typename std::enable_if<(C2>3)>::type>
T& a()
{
return v_[3];
}
const T& r() const { return v_[0]; }
const T& g() const { return v_[1]; }
const T& b() const { return v_[2]; }
template <int C2 = C,
typename = typename std::enable_if<(C2>3)>::type>
const T& a() const
{
return v_[3];
}
private:
Values v_;
};
You can then use it like this:
int main()
{
Color<3,int> c3;
Color<4,int> c4;
c3.v()[0] = 1;
c3.v()[1] = 2;
c3.v()[2] = 3;
std::cout <<
c3.r() << "," <<
c3.g() <<"," <<
c3.b() << "\n";
c4.v()[0] = 1;
c4.v()[1] = 2;
c4.v()[2] = 3;
c4.v()[3] = 4;
std::cout <<
c4.r() << "," <<
c4.g() << "," <<
c4.b() << "," <<
c4.a() << "\n";
}

Okay, so now #VaughnCato had this one out before me, but I'll still post my answer using std::enable_if. It declares Color as struct, because there is really no point in having a class when everything is public (and there is no good reason to declare the data member [v in the question] private), adds template aliases for a bit more syntactic sugar and uses static_assert to make sure the user doesn't use weird values for the template parameters. It also uses std::enable_if in a slightly different manner, which I would argue is a bit more readable.
#include <type_traits>
#include <cstdint>
template<unsigned nChans, typename T = std::uint8_t>
struct Color
{
static_assert(nChans >= 3 || nChans <= 4, "number of color channels can only be 3 or 4");
// allow integral types only
//static_assert(std::is_integral<T>::value, "T has to be an integral type");
// also allow floating-point types
static_assert(std::is_arithmetic<T>::value, "T has to be an arithmetic (integral or floating-point) type");
T data[nChans];
T& r() { return data[0]; }
T& g() { return data[1]; }
T& b() { return data[2]; }
//template<typename U = T, typename EnableIfT = std::enable_if<(nChans == 4), U>::type> // C++11
template<typename U = T, typename EnableIfT = std::enable_if_t<(nChans == 4), U>> // C++14
T& a() { return data[3]; }
const T& r() const { return data[0]; }
const T& g() const { return data[1]; }
const T& b() const { return data[2]; }
//template<typename U = T, typename EnableIfT = std::enable_if<(nChans == 4), U>::type>
template<typename U = T, typename EnableIfT = std::enable_if_t<(nChans == 4), U>>
T const& a() const { return data[3]; }
};
template<typename T = std::uint8_t> using RgbColor = Color<3, T>;
template<typename T = std::uint8_t> using RgbaColor = Color<4, T>;

Related

Enable Different Member Functions Depending On If Type Is POD

I believe this is fairly simply to achieve, but I can't figure out how.
Take the following example class:
class Example {
public:
template <typename T>
size_t foo(T& v) const;
};
How can I provide two implementations for this method depending on if T is a POD? I know there is an std::is_pod type trait, but I can't figure out how to have it enable the correct function.
I also need to be able to provide specific specializations for certain types of T regardless of if they are PODs or not. For example, I want to be able to write:
template <>
size_t foo<uint8_t>(uint8_t& b);
While all other types of T are chosen based upon being PODs or not.
EDIT
I have been looking at the information everyone has been giving and have come up with the following, however, this still does not work (throws a compiler error). I can't understand why.
class Example {
public:
template <typename T, bool U = std::is_trivially_copyable<T>::value>
size_t foo(T& v) const;
};
template <typename T>
size_t Example::foo<T, true>(T& v) const {
//Do something if T is mem copyable
}
template <typename T>
size_t Example::foo<T, false>(T& v) const {
//Do something if T is not mem copyable
}
Which results in "non-class, non-variable partial specialization 'foo<T, true>' is not allowed"
You can do it in the following way.
#include <iostream>
#include <type_traits>
struct A {
int m;
};
struct B {
int m1;
private:
int m2;
};
struct C {
virtual void foo() {};
};
// is_pod is deprecated since C++ 20
template <typename T>
std::enable_if_t<std::is_pod_v<T>, size_t> foo(const T& pod)
{
std::cout << &pod << " is_pod\n";
return 0;
}
template <>
size_t foo<uint8_t>(const uint8_t& b)
{
std::cout << int(b) << " is uint8_t\n";
return 1;
}
template <>
size_t foo<int>(const int& b)
{
std::cout << int(b) << " is int\n";
return 1;
}
int main()
{
uint8_t a = 2;
foo(a);
foo(22);
// will compile
A instance;
foo(instance);
// will not compile
B b;
//foo(b);
// will not compile
C c;
//foo(c);
}
output
2 is uint8_t
22 is int
010FFA64 is_pod
Here is what I did to get it to work correctly:
#include <type_traits>
#include <iostream>
class Example {
public:
Example(int a) : _a(a) {}
virtual void bar() {}
template <typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, size_t>::type = 0>
size_t foo(T& v) const {
std::cout << "T is trivially copyable" << std::endl;
return sizeof(T);
}
template <typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, size_t>::type = 0>
size_t foo(T& v) const {
std::cout << "T is not trivially copyable" << std::endl;
return sizeof(T);
}
private:
int _a;
int _b;
int _c;
};
template <>
size_t Example::foo<unsigned int>(unsigned int& v) const {
std::cout << "T is unsigned int" << std::endl;
return sizeof(unsigned int);
}
int main() {
Example e(10);
int a;
e.foo(a);
char b;
e.foo(b);
e.foo(e);
unsigned int c;
e.foo(c);
return 0;
}
The output of which looks like:
T is trivially copyable
T is trivially copyable
T is not trivially copyable
T is unsigned int
This is based upon the following Provide/enable method to in a class based on the template type

Sum types in C++

At work, I ran into a situation where the best type to describe the result returned from a function would be std::variant<uint64_t, uint64_t> - of course, this isn't valid C++, because you can't have two variants of the same type. I could represent this as a std::pair<bool, uint64_t>, or where the first element of the pair is an enum, but this is a special case; a std::variant<uint64_t, uint64_t, bool> isn't so neatly representable, and my functional programming background really made me want Either - so I went to try to implement it, using the Visitor pattern as I have been able to do in other languages without native support for sum types:
template <typename A, typename B, typename C>
class EitherVisitor {
virtual C onLeft(const A& left) = 0;
virtual C onRight(const B& right) = 0;
};
template <typename A, typename B>
class Either {
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) = 0;
};
template <typename A, typename B>
class Left: Either<A, B> {
private:
A value;
public:
Left(const A& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onLeft(value);
}
};
template <typename A, typename B>
class Right: Either<A, B> {
private:
B value;
public:
Right(const B& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onRight(value);
}
};
C++ rejects this, because the template method Accept cannot be virtual. Is there a workaround to this limitation, that would allow me to correctly represent the fundamental sum type in terms of its f-algebra and catamorphism?
Perhaps the simplest solution is a lightweight wrapper around T for Right and Left?
Basically a strong type alias (could also use Boost's strong typedef)
template<class T>
struct Left
{
T val;
};
template<class T>
struct Right
{
T val;
};
And then we can distinguish between them for visitation:
template<class T, class U>
using Either = std::variant<Left<T>, Right<U>>;
Either<int, int> TrySomething()
{
if (rand() % 2 == 0) // get off my case about rand(), I know it's bad
return Left<int>{0};
else
return Right<int>{0};
}
struct visitor
{
template<class T>
void operator()(const Left<T>& val_wrapper)
{
std::cout << "Success! Value is: " << val_wrapper.val << std::endl;
}
template<class T>
void operator()(const Right<T>& val_wrapper)
{
std::cout << "Failure! Value is: " << val_wrapper.val << std::endl;
}
};
int main()
{
visitor v;
for (size_t i = 0; i < 10; ++i)
{
auto res = TrySomething();
std::visit(v, res);
}
}
Demo
std::variant<X,X> is valid C++.
It is a bit awkward to use, because std::visit doesn't give you the index, and std::get<X> won't work either.
The way you can work around this is to create a variant-of-indexes, which is like a strong enum.
template<std::size_t i>
using index_t = std::integral_constant<std::size_t, i>;
template<std::size_t i>
constexpr index_t<i> index = {};
template<std::size_t...Is>
using number = std::variant< index_t<Is>... >;
namespace helpers {
template<class X>
struct number_helper;
template<std::size_t...Is>
struct number_helper<std::index_sequence<Is...>> {
using type=number<Is...>;
};
}
template<std::size_t N>
using alternative = typename helpers::number_helper<std::make_index_sequence<N>>::type;
we can then extract the alternative from a variant:
namespace helpers {
template<class...Ts, std::size_t...Is, class R=alternative<sizeof...(Ts)>>
constexpr R get_alternative( std::variant<Ts...> const& v, std::index_sequence<Is...> ) {
constexpr R retvals[] = {
R(index<Is>)...
};
return retvals[v.index()];
}
}
template<class...Ts>
constexpr alternative<sizeof...(Ts)> get_alternative( std::variant<Ts...> const& v )
{
return helpers::get_alternative(v, std::make_index_sequence<sizeof...(Ts)>{});
}
so now you have a std::variant<int, int>, you can
auto which = get_alternative( var );
and which is a variant, represented at runtime by an integer which is the index of the active type in var. You can:
std::variant<int, int> var( std::in_place_index_t<1>{}, 7 );
auto which = get_alternative( var );
std::visit( [&var](auto I) {
std::cout << std::get<I>(var) << "\n";
}, get_alternative(var) );
and get access to which of the alternative possibilities in var is active with a compile time constant.
The get_alternative(variant), I find, makes variant<X,X,X> much more usable, and fills in the hole I think you might be running into.
Live example.
Now if you don't need a compile-time index of which one is active, you can just call var.index(), and visit via visit( lambda, var ).
When you construct the variant, you do need the compile time index to do a variant<int, int> var( std::in_place_index_t<0>{}, 7 ). The wording is a bit awkward, because while C++ supports variants of multiples of the same type, it considers them a bit less likely than a "standard" disjoint variant outside of generic code.
But I've used this alternative and get_alternative like code to support functional programming like data glue code before.

Hashing types at compile-time in C++17/C++2a

Consider the following code:
#include <iostream>
#include <type_traits>
template <class T>
constexpr std::size_t type_hash(T) noexcept
{
// Compute a hash for the type
// DO SOMETHING SMART HERE
}
int main(int argc, char* argv[])
{
auto x = []{};
auto y = []{};
auto z = x;
std::cout << std::is_same_v<decltype(x), decltype(y)> << std::endl; // 0
std::cout << std::is_same_v<decltype(x), decltype(z)> << std::endl; // 1
constexpr std::size_t xhash = type_hash(x);
constexpr std::size_t yhash = type_hash(y);
constexpr std::size_t zhash = type_hash(z);
std::cout << (xhash == yhash) << std::endl; // should be 0
std::cout << (yhash == zhash) << std::endl; // should be 1
return 0;
}
I would like the type_hash function to return a hash key unique to the type, at compile-time. Is there a way to do that in C++17, or in C++2a (ideally only relying on the standard and without relying compiler intrinsics)?
I doubt that's possible with purely the standard C++.
But there is a solution that will work on most major compilers (at least GCC, Clang, and MSVC). You could hash strings returned by the following function:
template <typename T> constexpr const char *foo()
{
#ifdef _MSC_VER
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}
I don't know a way to obtain a std::size_t for the hash.
But if you accept a pointer to something, maybe you can take the address of a static member in a template class.
I mean... something as follows
#include <iostream>
#include <type_traits>
template <typename>
struct type_hash
{
static constexpr int i { };
static constexpr int const * value { &i };
};
template <typename T>
static constexpr auto type_hash_v = type_hash<T>::value;
int main ()
{
auto x = []{};
auto y = []{};
auto z = x;
std::cout << std::is_same_v<decltype(x), decltype(y)> << std::endl; // 0
std::cout << std::is_same_v<decltype(x), decltype(z)> << std::endl; // 1
constexpr auto xhash = type_hash_v<decltype(x)>;
constexpr auto yhash = type_hash_v<decltype(y)>;
constexpr auto zhash = type_hash_v<decltype(z)>;
std::cout << (xhash == yhash) << std::endl; // should be 0
std::cout << (xhash == zhash) << std::endl; // should be 1
} // ...........^^^^^ xhash, not yhash
If you really want type_hash as a function, I suppose you could simply create a function that return the type_hash_v<T> of the type received.
Based on HolyBlackCat answer, a constexpr template variable which is a (naive) implementation of the hash of a type:
template <typename T>
constexpr std::size_t Hash()
{
std::size_t result{};
#ifdef _MSC_VER
#define F __FUNCSIG__
#else
#define F __PRETTY_FUNCTION__
#endif
for (const auto &c : F)
(result ^= c) <<= 1;
return result;
}
template <typename T>
constexpr std::size_t constexpr_hash = Hash<T>();
Can be used as shown below:
constexpr auto f = constexpr_hash<float>;
constexpr auto i = constexpr_hash<int>;
Check on godbolt that the values are indeed, computed at compile time.
I will agree with the other answers that it's not generally possible as-stated in standard C++ yet, but we may solve a constrained version of the problem.
Since this is all compile-time programming, we cannot have mutable state, so if you're willing to use a new variable for each state change, then something like this is possible:
hash_state1 = hash(type1)
hash_state2 = hash(type2, hash_state1)
hash_state3 = hash(type3, hash_state2)
Where "hash_state" is really just a unique typelist of all the types we've hashed so far. It can also provide a size_t value as a result of hashing a new type.
If a type that we seek to hash is already present in the typelist, we return the index of that type.
This requires quite a bit of boilerplate:
Ensuring types are unique within a typelist: I used #Deduplicator's answer here: https://stackoverflow.com/a/56259838/27678
Finding a type in a unique typelist
Using if constexpr to check if a type is in the typelist (C++17)
Live Demo
Part 1: a unique typelist:
Again, all credit to #Deduplicator's answer here on this part. The following code saves compile-time performance by doing lookups on a typelist in O(log N) time thanks to leaning on the implementation of tuple-cat.
The code is written almost frustratingly generically, but the nice part is that it allows you to work with any generic typelist (tuple, variant, something custom).
namespace detail {
template <template <class...> class TT, template <class...> class UU, class... Us>
auto pack(UU<Us...>)
-> std::tuple<TT<Us>...>;
template <template <class...> class TT, class... Ts>
auto unpack(std::tuple<TT<Ts>...>)
-> TT<Ts...>;
template <std::size_t N, class T>
using TET = std::tuple_element_t<N, T>;
template <std::size_t N, class T, std::size_t... Is>
auto remove_duplicates_pack_first(T, std::index_sequence<Is...>)
-> std::conditional_t<(... || (N > Is && std::is_same_v<TET<N, T>, TET<Is, T>>)), std::tuple<>, std::tuple<TET<N, T>>>;
template <template <class...> class TT, class... Ts, std::size_t... Is>
auto remove_duplicates(std::tuple<TT<Ts>...> t, std::index_sequence<Is...> is)
-> decltype(std::tuple_cat(remove_duplicates_pack_first<Is>(t, is)...));
template <template <class...> class TT, class... Ts>
auto remove_duplicates(TT<Ts...> t)
-> decltype(unpack<TT>(remove_duplicates<TT>(pack<TT>(t), std::make_index_sequence<sizeof...(Ts)>())));
}
template <class T>
using remove_duplicates_t = decltype(detail::remove_duplicates(std::declval<T>()));
Next, I declare my own custom typelist for using the above code. A pretty straightforward empty struct that most of you have seen before:
template<class...> struct typelist{};
Part 2: our "hash_state"
"hash_state", which I'm calling hash_token:
template<size_t N, class...Ts>
struct hash_token
{
template<size_t M, class... Us>
constexpr bool operator ==(const hash_token<M, Us...>&)const{return N == M;}
constexpr size_t value() const{return N;}
};
Simply encapsulates a size_t for the hash value (which you can also access via the value() function) and a comparator to check if two hash_tokens are identical (because you can have two different type lists but the same hash value. e.g., if you hash int to get a token and then compare that token to one where you've hashed (int, float, char, int)).
Part 3: type_hash function
Finally our type_hash function:
template<class T, size_t N, class... Ts>
constexpr auto type_hash(T, hash_token<N, Ts...>) noexcept
{
if constexpr(std::is_same_v<remove_duplicates_t<typelist<Ts..., T>>, typelist<Ts...>>)
{
return hash_token<detail::index_of<T, Ts...>(), Ts...>{};
}
else
{
return hash_token<N+1, Ts..., T>{};
}
}
template<class T>
constexpr auto type_hash(T) noexcept
{
return hash_token<0, T>{};
}
The first overload is for the generic case; you've already "hashed" a number of types, and you want to hash yet another one. It checks to see if the type you're hashing has already been hashed, and if so, it returns the index of the type in the unique type list.
To accomplish getting the index of a type in a typelist, I used simple template expansion to save some compile time template instantiations (avoiding a recursive lookup):
// find the first index of T in Ts (assuming T is in Ts)
template<class T, class... Ts>
constexpr size_t index_of()
{
size_t index = 0;
size_t toReturn = 0;
using swallow = size_t[];
(void)swallow{0, (void(std::is_same_v<T, Ts> ? toReturn = index : index), ++index)...};
return toReturn;
}
The second overload of type_hash is for creating an initial hash_token starting at 0.
Usage:
int main()
{
auto x = []{};
auto y = []{};
auto z = x;
std::cout << std::is_same_v<decltype(x), decltype(y)> << std::endl; // 0
std::cout << std::is_same_v<decltype(x), decltype(z)> << std::endl; // 1
constexpr auto xtoken = type_hash(x);
constexpr auto xytoken = type_hash(y, xtoken);
constexpr auto xyztoken = type_hash(z, xytoken);
std::cout << (xtoken == xytoken) << std::endl; // 0
std::cout << (xtoken == xyztoken) << std::endl; // 1
}
Conclusion:
Not really useful in a lot of code, but this may help solve some constrained meta-programming problems.
I don't think it is possible. "hash key unique to the type" sounds like you are looking for a perfect hash (no collisions). Even if we ignore that size_t has a finite number of possible values, in general we can't know all the types because of things like shared libraries.
Do you need it to persist between runs? If not, you can set up a registration scheme.
I would like to improve upon #max66's answer (which is absolutely brilliant and simple by the way, I wish I thought of it)
<TL;DR>
Put inline on the static variables in max66's answer and it will make sure the same static value is present across all translation units.
</TL;DR>
If you have multiple translation units, then, typically, multiple instances of a static variable (in max66's case i) will be created, changing the value of the hash, this could be a problem, say I have a function getHash that I want to use to check if two types are the same
#include <iostream>
#include <type_traits>
#include <memory>
// <From max66's answer>
template <typename>
struct type_hash
{
static constexpr int i { };
static constexpr int const * value { &i };
};
template <typename T>
static constexpr auto type_hash_v = type_hash<T>::value;
// </From max66's answer>
struct AnyBase {
using PointerType = std::unique_ptr<AnyBase>;
constexpr virtual bool equal(const PointerType& other) const noexcept = 0;
constexpr virtual const int* typeHash() const noexcept = 0;
};
template<typename ParameterType>
struct Any : public AnyBase
{
using BasePointerType = std::unique_ptr<AnyBase>;
using Type = ParameterType;
Type value;
constexpr Any(Type value) noexcept : value(value) {}
constexpr virtual bool equal(const BasePointerType& other) const noexcept final
{
if(other->typeHash() == typeHash()) {
const auto unwrapped = dynamic_cast<const Any<Type>*>(other.get());
return unwrapped->value == value;
}
return false;
}
constexpr virtual const int* typeHash() const noexcept final {
return type_hash_v<Type>;
}
};
using AnyType = std::unique_ptr<AnyBase>;
template<typename ParameterType>
AnyType makeAny(auto... initializationValues) {
return static_cast<AnyType>(std::make_unique<Any<ParameterType>>(initializationValues...));
}
int main()
{
AnyType any0 = makeAny<int>(4);
AnyType any1 = makeAny<int>(2);
AnyType any2 = makeAny<int>(4);
AnyType any3 = makeAny<char>('A');
std::cout << "Hash Codes: "
<< any0->typeHash() << "\n"
<< any1->typeHash() << "\n"
<< any2->typeHash() << "\n"
<< any3->typeHash() << "\n";
std::cout
<< "any0 == any1? " << any0->equal(any1) << "\n" // False within translation unit
<< "any0 == any2? " << any0->equal(any2) << "\n" // True within translation unit
<< "any0 == any3? " << any0->equal(any3) << "\n"; // False within translation unit
return 0;
}
If I instantiate two Any<int>'s in two different translation units, they may have two different hashes, because i is static and is likely to have a different addresses across the translation units, therefore when I try to compare Any<int>'s it will fail even if they have the same type and value.
I learned from Daisy Hollman's presentation at CppNow (slides here) that the C++ standard guarantees a single persistent instantiation of an object across translation units
Unfortunately the way she does type registration at the beginning of the presentation is not constexprable because it relies on a static mutable variable within a function. However using this knowledge we can tweak max66's approach, lets modify the code from before
#include <iostream>
#include <type_traits>
#include <memory>
#include <bit>
template<typename ParameterType>
struct Registrar
{
constexpr inline static const uintptr_t getHash() { // ACCORDING TOO C++ STANDARD INLINE GUARANTEES ONE COPY ACROSS ALL TRANSLATION UNITS
return std::bit_cast<uintptr_t>(&hashObject);
}
protected:
constinit inline static const size_t hashObject = 0; // ACCORDING TOO C++ STANDARD INLINE GUARANTEES ONE COPY ACROSS ALL TRANSLATION UNITS
};
struct AnyBase {
using PointerType = std::unique_ptr<AnyBase>;
constexpr virtual bool equal(const PointerType& other) const noexcept = 0;
constexpr virtual const uintptr_t typeHash() const noexcept = 0;
};
template<typename ParameterType>
struct Any : public AnyBase
{
using BasePointerType = std::unique_ptr<AnyBase>;
using Type = ParameterType;
Type value;
constexpr Any(Type value) noexcept : value(value) {}
constexpr virtual bool equal(const BasePointerType& other) const noexcept final
{
if(other->typeHash() == typeHash()) {
const auto unwrapped = dynamic_cast<const Any<Type>*>(other.get());
return unwrapped->value == value;
}
return false;
}
constexpr virtual const uintptr_t typeHash() const noexcept final {
return Registrar<Type>::getHash();
}
};
using AnyType = std::unique_ptr<AnyBase>;
template<typename ParameterType>
AnyType makeAny(auto... initializationValues) {
return static_cast<AnyType>(std::make_unique<Any<ParameterType>>(initializationValues...));
}
int main()
{
AnyType any0 = makeAny<int>(4);
AnyType any1 = makeAny<int>(2);
AnyType any2 = makeAny<int>(4);
AnyType any3 = makeAny<char>('A');
std::cout << "Hash Codes: "
<< any0->typeHash() << "\n"
<< any1->typeHash() << "\n"
<< any2->typeHash() << "\n"
<< any3->typeHash() << "\n";
std::cout
<< "any0 == any1? " << any0->equal(any1) << "\n" // False GUARANTEED across translation units
<< "any0 == any2? " << any0->equal(any2) << "\n" // True GUARANTEED across translation units
<< "any0 == any3? " << any0->equal(any3) << "\n"; // False GUARANTEED across translation units
return 0;
}
Now our hash is guaranteed across translation units (as I stated in all caps :) )
Thanks to #max66 and Daisy Hollman
And a note, I think you could further static_cast to size_t or something if you want from uintptr_t, both examples compile with gcc 12.2 with -std=c++23

complex constexpr alternatives

Consider
typedef std::complex<double> Complex;
Complex ComplexExpresion(int a) {return Complex(0,-a);}
Since one cannot write
template<typename D>
struct A
{
static constexpr Complex value = ComplexExpresion(D::value);
};
as an alternative one writes
template<typename D>
struct B
{
static const Complex value;
};
template<typename D>
const Complex B<D>::value = ComplexExpresion(D::value);
Consider now
template<typename D, int N>
struct C;
template<typename D>
struct C<D,1>
{
static const Complex value;
};
template<typename D>
const Complex C<D,1>::value = B<D>::value;
For some reasone
struct Data
{
static auto constexpr value =2;
};
int main()
{
using C = C<Data,1>;
std::cout << C::value;
}
prints the correct value(which is (0,-2) ) here but the same code prints (0,0) when complied by MSVC++
I have 2 questions
1) why it is so on MSVC++ and is there known workaround?
2) is there better alternative for struct A than struct B which is not exactly the same thing...
Looks like a compiler bug unless I'm missing something. This isn't really an answer, just sharing what I found. This is the smallest example I could deduce that exhibits the issue:
#include <iostream>
// using function is important
int func() { return 1; }
// template is imporant
template<class D>
struct B
{
static const int value;
};
// defined outside block is important
template<class D>
const int B<D>::value = func();
// going through C is important
struct C
{
static const int value;
};
const int C::value = B<int>::value;
int main()
{
// should print 1 but prints 0
std::cout << C::value << std::endl;
}
surprisingly this also trips up clang unless I specify func as constexpr or specify -stdlib=libc++ (at least on coliru)
I guess you can fix your issue by skipping one of the bits above. You can do static constexpr Complex value = ComplexExpresion(D::value); if you mark ComplexEspression as constexpr.

C++ replacing member variables with values from other types

I have a class T with n member variables, for example
class T{
ushort name;
ushort id;
double value;
.....etc...
};
I also have a collection of classes T1, T2...., each consisting of member variables
which are subsets of member variables of T (for lack of a better word, let me call
this a subset type of T). For example, T1 may be
class T1 {
ushort name;
double value;
};
which just picks up two members of T.
I would like to write a method
template <typename X>
T join(T t, X x)
where we return a class of type T, by replacing values of each member variable in t, with
those of x (provided X is a sub-type of T) and the other values of t remain the same.
I can think of doing this via specializations. But there should be an elegant method of doing this (perhaps detecting when a type X is a subset-type of T and doing the right thing).
I can think of doing this via specializations. But there should be an elegant method of doing this (perhaps detecting when a type X is a subset-type of T and doing the right thing).
"Detecting" is part of specialization. You should provide specializations for "subset"-types and provide no implementation for generic specialization (to provoke compilation error, when someone uses other types with that method).
If you don't want to provide specializations for all subset types. You can try to use the member detector idiom: Member Detector, or __if_exist if you are using MSVC.
So you only need to write [number of members in T] * 2 macros(and if use MSVC, you don't need the SetXXX) instead of specializing all possible combinations of members in T
CREATE_MEMBER_DETECTOR(name);
CREATE_MEMBER_DETECTOR(id);
CREATE_MEMBER_DETECTOR(value);
......
template<int N, typename T, typename R>
class SetName
{
public:
void operator()(T& t, R& r)
{
}
};
template<typename T, typename R>
class SetName<1, T, R>
{
public:
void operator()(T& t, R& r)
{
t.name = r.name;
}
};
......
(can be macros too)
And the join() should be:
template <typename SUBSET>
T join(T t, SUBSET x)
{
SetName<Detect_name<SUBSET>::value, T, SUBSET>()(t, x);
SetValue<Detect_value<SUBSET>::value, T, SUBSET>()(t, x);
......
return t;
}
I would implement conversion from T1...Tn to T (or some class that is derived from T and has info which members are actually set), and then implement join() function in terms of T. Don't think this is good place for template magic actually
Try this:
#include <iostream>
#include <typeifo>
using namespace std;
template<typename T>
struct SetBase
{
T first;
T second;
SetBase(const T& first = T(), const T& second = T())
: first(first), second(second) {}
};
template<typename T>
struct Set : public SetBase<T>
{
short name_id;
Set(const T& first = T(), const T& second = T(), const short& name) :
SetBase<T>(first, second), name_id(name){}
};
template<typename Class, typename BaseClass>
Class* join(Class **a, BaseClass *b)
{
if(typeid(Class) != typeid(BaseClass))
{
Class* retval = new Class(*static_cast<Class*>(b));
retval->name_id = (*a)->name_id;
*a = retval;
}
else
{
Class* retval = new Class(*b);
*a = retval;
}
return retval;
}
int main()
{
Set<int> *a = new Set<int>(1, 2, 3);
SetBase<int> *b = new SetBase<int>(4, 5);
cout << join(&a, b)->first << " " << join(&a, b)->second << " " << join(&a, b)->name_id << "\n";
cout << a->first << " " << a->second << " " << a->name_id << "\n";
return 0;
}
The Set class is public derived from SetBase, so the cast that I use is valid