Is there a general approach to solve this type of circular dependencies in template or is it impossible to make work?
#include <tuple>
template<class... T>
struct A {
std::tuple<T...> t;
};
template<class type_of_A>
struct D1 {
type_of_A* p;
};
template<class type_of_A>
struct D2 {
type_of_A* p;
};
using A_type = A<D1<???>, D2<???>>; // <------
int main() { }
As usual, insert a named indirection into the mix to break the infinite recursion:
template<class... T>
struct A {
std::tuple<T...> t;
};
template<class type_of_A>
struct D1 {
typename type_of_A::type* p; // Indirection
};
template<class type_of_A>
struct D2 {
typename type_of_A::type* p; // Indirection
};
// Type factory while we're at it
template <template <class> class... Ds>
struct MakeA {
using type = A<Ds<MakeA>...>; // Hey, that's me!
};
using A_type = typename MakeA<D1, D2>::type;
The behaviour of MakeAs injected-class-name is a bonus, but we could spell it out as MakeA<Ds...>.
See it live on Coliru
Related
I am new to C++20. The intention here is to have a template class which has value whose type would be the underlying type of T that's passed in.
So in case of T being:
std::optional<char>, it's char value
int, it's just int value.
Is there any better way to extract the types than through struct TypeExtract? More or a generic solution in C++20 perhaps? Given if the class could take more than just std::optional<int> or just a primitive type?
Can the condition in foo be improved specially with the way val is initialized?
template<typename T>
constexpr bool is_optional = false;
template<typename T>
constexpr bool is_optional<std::optional<T>> = true;
template<typename T>
struct TypeExtract
{
using type = T;
};
template<typename T>
struct TypeExtract<std::optional<T>>
{
using type = T;
};
template <typename T>
concept is_integral = std::is_integral_v<typename TypeExtract<T>::type>;
template <is_integral T>
class A
{
using Type = typename TypeExtract<T>::type;
Type val;
void foo(T value)
{
if constexpr (is_optional<T>)
{
val = *value;
}
else
{
val = value;
}
}
};
int main()
{
A<char> a1;
A<std::optional<int>> a2;
// A<double> a3; // fails
}
It looks like you're trying to extract first template parameter from a class template and keep on unwinding templates until you get to a non-template type. In that case you could make a type trait that is specialized for types instantiated from templates:
// primary template
template<class T, class...>
struct type {
using value_type = T;
};
// specialization for template instantiated types
template<template<class, class...> class T, class F, class... Rest>
struct type<T<F, Rest...>> {
using value_type = typename type<F>::value_type;
};
// helper alias
template<class... Ts>
using type_t = typename type<Ts...>::value_type;
You could then use it like so:
int main() {
type_t<char> a1;
type_t<std::optional<int>> a2;
type_t<double, int> a3;
static_assert(std::is_same_v<decltype(a1), char>);
static_assert(std::is_same_v<decltype(a2), int>);
static_assert(std::is_same_v<decltype(a3), double>);
}
There is no good or bad here, it's a matter of style and convention, but personally I would get rid of if constexpr and take advantage of trailing requires for the sake of reducing function's cyclomatic complexity. On the other hand, that add some boilerplate. The choice is yours.
Not much can be done about type extraction, though I would probably use a templated base and import its member(s) instead of importing the type into the class. Not a big deal, but it feels more idiomatic to me.
As for concepts, I'd probably use more library-provided ones in the place of type traits.
Side note: consider using assert, .value() or similar function when assigning from the optional to ensure it's not empty.
All in all, I'd probably write your code somewhat this way:
#include <concepts>
#include <type_traits>
#include <optional>
template<typename T>
concept StdOptional = std::same_as<std::optional<typename T::value_type>, T>;
template<typename T>
concept OptionalIntegral = StdOptional<T> and std::integral<typename T::value_type>;
template<typename T>
concept OptionalOrOptionalIntegral = std::integral<T> or OptionalIntegral<T>;
template<typename>
struct ABase;
template<std::integral T>
struct ABase<T>
{
T value;
};
template<OptionalIntegral T>
struct ABase<T>
{
typename T::value_type value;
};
template<OptionalOrOptionalIntegral T>
class A : ABase<T>
{
using ABase<T>::value;
public:
void setValue(T val) requires(std::integral<T>)
{
value = val;
}
void setValue(T val) requires(OptionalIntegral<T>)
{
value = val.value();
}
};
Demo: https://godbolt.org/z/dzvr9xbGr
I have some CRTP dependency that I am not sure how to resolve. Ideally I want to put as many things as possible in the base class, like functions, so I do not have to redefine those for every class that inherits those. This seems to cause an issue with the initialization order, where result_type is dependent on the type that is yet to be initialized. Here is an example: https://godbolt.org/z/YpfcPB
And here is the code:
template<typename T>
struct CRTP_Derived;
template<typename Derived>
struct CRTP
{
using result_type = typename Derived::result_type;
};
template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>>
{
using result_type = T;
};
int main()
{
CRTP_Derived<int> a;
return 0;
}
I've also used a separate traits type for issues like this. You can reduce the needed boilerplate a little if you make the traits a second template parameter, instead of requiring users to specialize a separate template:
template<typename Derived, typename Traits>
struct CRTP
{
using result_type = typename Traits::result_type;
};
template<typename T>
struct CRTP_Derived_Traits
{
using result_type = T;
};
template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>, CRTP_Derived_Traits<T>>
{
};
int main()
{
CRTP_Derived<int> a;
return 0;
}
A workaround I found is taking out the typedef in a separate class, still I would be glad to see other solutions.
https://godbolt.org/z/a7NCE2
template<typename T>
struct CRTP_Derived;
template<typename Derived>
struct traits;
template<typename T>
struct traits<CRTP_Derived<T>>
{
using result_type = T;
};
template<typename Derived>
struct CRTP
{
using result_type = typename traits<Derived>::result_type;
};
template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>>
{
using result_type = T;
};
int main()
{
CRTP_Derived<int> a;
return 0;
}
I would like to know how to solve the following problem (C++17):
suppose there are several template classes, inherited from each other in CRTP-like fashion (single inheritance only). For a given instantiated template base class, find the class that is furthest from it down the inheritance chain.
I first thought that is should be pretty easy, but was not able to accomplish this.
To simplify, suppose that every root and every intermediate class has using DerivedT = Derived in its public area.
Example:
template <class T>
struct GetDeepest {
using Type = ...;
};
template <class T>
struct A {
using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
GetDeepest<A<D>>::Type == D;
GetDeepest<B<C>>::Type == C;
GetDeepest<A<B<C>>>::Type == C;
...
First implementation I've tried:
template <class T>
struct GetDeepest {
template <class Test, class = typename Test::DerivedT>
static std::true_type Helper(const Test&);
static std::false_type Helper(...);
using HelperType = decltype(Helper(std::declval<T>()));
using Type = std::conditional_t<std::is_same_v<std::true_type, HelperType>,
GetDeepest<typename T::DerivedT>::Type,
T>;
};
Second implementation I've tried:
template <class T>
struct HasNext {
template <class Test, class = typename Test::DerivedT>
static std::true_type Helper(const Test&);
static std::false_type Helper(...);
using HelperType = decltype(Helper(std::declval<T>()));
static const bool value = std::is_same_v<std::true_type, HelperType>;
};
template <class T>
auto GetDeepestHelper(const T& val) {
if constexpr(HasNext<T>::value) {
return GetDeepestHelper(std::declval<typename T::DerivedT>());
} else {
return val;
}
}
template <class T>
struct GetDeepest {
using Type = decltype(GetDeepestLevelHelper(std::declval<T>()));
};
None of them compile.
First one -- because of incomplete type of GetDeepest<T> in statement using Type = ..., second because of recursive call of a function with auto as a return type.
Is it even possible to implement GetDeepest<T> class with such properties? Now I'm very curious, even if it might be not the best way to accomplish what I want.
Thanks!
I'm not sure if I fully understand the question so feel free to ask me in comments.
But I think this should work:
#include <type_traits>
template<typename T>
struct GetDeepest
{
using Type = T;
};
template<template<typename> class DT, typename T>
struct GetDeepest<DT<T>>
{
using Type = typename GetDeepest<T>::Type;
};
template <class T>
struct A {
using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
int main()
{
static_assert(std::is_same<GetDeepest<A<D>>::Type, D>::value);
static_assert(std::is_same<GetDeepest<B<C>>::Type, C>::value);
static_assert(std::is_same<GetDeepest<A<B<C>>>::Type, C>::value);
}
Say you have the following code:
class A {
bool _attribute1;
};
// Arbitrarily using std::string, not the point of this question
std::string serialize(const A&);
Now a developer adds a new bool _attribute2 to class A and forgets to update the serialize function, which leads to a bug at runtime. (Already been there ?)
Is there a way to turn this issue into compile-time error ? As C++ doesn't support reflection, I have the feeling this is impossible, but I may be missing something.
If you are using c++1z you could make use of structured binding:
struct S {
bool b;
//bool c; // causes error
};
int main() {
S s;
auto [x] = s;
(void)x;
}
[live demo]
The following one should work with C++11.
A bit tricky indeed, it's based on a comment of #SamVarshavchik:
#include<cstddef>
#include<functional>
template<std::size_t> struct Int { int i; };
template<std::size_t> struct Char { char c; };
template<std::size_t> struct Bool { bool c; };
template<typename, template<std::size_t> class...>
struct Base;
template<template<std::size_t> class... T, std::size_t... I>
struct Base<std::index_sequence<I...>, T...>: T<I>... {};
template<template<std::size_t> class... T>
struct Check final: Base<std::make_index_sequence<sizeof...(T)>, T...> {};
class A final {
bool _attribute1;
bool _attribute2;
private:
char _attribute3;
// int _attribute4;
};
void serialize(const A &) {
static_assert(sizeof(A) == sizeof(Check<Bool, Bool, Char>), "!");
// do whatever you want here...
}
int main() {
serialize(A{});
}
The basic idea is to list all the types of the data members and define a new type from them with a mixin. Then it's a matter of putting a static_assert in the right place.
Note that private data members are taken in consideration too.
There exist some corner cases that could break it, but maybe it can work for your real code.
As a side note, it can be further simplified if C++14 is an option:
#include<cstddef>
template<typename... T>
constexpr std::size_t size() {
std::size_t s = 0;
std::size_t _[] = { s += sizeof(T)... };
(void)_;
return s;
}
class A final {
bool _attribute1;
bool _attribute2;
private:
char _attribute3;
// int _attribute4;
};
void serialize(const A &) {
static_assert(sizeof(A) == size<bool, bool, char>(), "!");
// ...
}
int main() {
serialize(A{});
}
If you are doomed to use c++11 and still you are interested in serializing only the public fields you could create trait testing if the type can be constructed using list initialization with a given parameters types but not even one more (of any type):
#include <type_traits>
struct default_param {
template <class T>
operator T();
};
template <class T, class...>
using typer = T;
template <class, class, class... Args>
struct cannot_one_more: std::true_type {};
template <class Tested, class... Args>
struct cannot_one_more<typer<void, decltype(Tested{std::declval<Args>()..., default_param{}})>, Tested, Args...>: std::false_type {
};
template <class...>
struct is_list_constructable: std::false_type {};
template <class Tested, class... Args>
struct is_list_constructable<Tested(Args...)>: is_list_constructable<void, Tested, Args...> { };
template <class Tested, class... Args>
struct is_list_constructable<typer<void, decltype(Tested{std::declval<Args>()...}), typename std::enable_if<cannot_one_more<void, Tested, Args...>::value>::type>, Tested, Args...>: std::true_type { };
struct S {
bool b;
//bool c; // causes error
};
int main() {
static_assert(is_list_constructable<S(bool)>::value, "!");
}
[live demo]
This is possible:
struct A {
//void f(); < not declared in struct A
};
template<typename T>
struct Wrapper {
T t;
void call_f() { t.f(); }
};
int main() {
Wrapper<A> w;
}
This compiled fine, as long as w.call_f() is not called. w.call_f() can not be instantiated because A::f does not exist.
I'm having a situation with such a wrapper template that gets used with different T types, which do not always implement all parts of the interface. (Mainly to avoid code duplication).
This does not work:
struct A {
//using i_type = int; < not declared/defined
};
template<typename T>
struct Wrapper {
using its_i_type = typename T::i_type;
// compile error, even if `i_type` gets never used
};
int main() {
Wrapper<A> w;
}
neither does this:
struct A {
//using i_type = int; < not declared/defined
};
template<typename T>
struct Wrapper {
typename T::i_type call_f() { return 0; }
// does not compile, even if `call_f()` is never instantiated
};
int main() {
Wrapper<A> w;
}
Is there a good way to handle these situations, without a lot of code duplication (like a specialization for Wrapper, etc.)?
You can defer the type deduction of its_i_type. Basically, you create a simple wrapper that you must go through.
To extend it to other types you require, (I wanted to suggest type_traits-like solution, but since you don't want specializations) you could define all the types you need:
template<typename T>
struct Wrapper {
private:
template<typename U> struct i_typper { using type = typename U::i_type; };
template<typename U> struct k_typper { using type = typename U::k_type; };
template<typename U> struct p_typper { using type = typename U::p_type; };
public:
using i_trait = i_typper<T>;
using k_trait = k_typper<T>;
using p_trait = p_typper<T>;
};
Example:
struct A { using i_type = int; };
struct B { using i_type = int; using k_type = float; };
int main() {
Wrapper<A> w; //Works now.
Wrapper<A>::i_trait::type mk1; //Works
Wrapper<A>::k_trait::type mk2; //Fails, not defined
Wrapper<B>::i_trait::type mk3; //Works
Wrapper<B>::k_trait::type mk4; //Works
}
For the case of:
template<typename T>
struct Wrapper {
typename T::i_type call_f() { return 0; }
// does not compile, even if `call_f()` is never instantiated
};
You have few options here:
make that function a member function template
Use some form of type_traits mechanism, which will still involve specialization
Go the way of abstracting common Wrapper stuff in a base class WrapperBase;
For the first option, you'll have to modify it a bit to further defer deduction
template<typename T>
struct Wrapper {
private:
template<typename U, typename> struct i_typper { using type = typename U::i_type; };
template<typename U, typename> struct k_typper { using type = typename U::k_type; };
template<typename U, typename> struct p_typper { using type = typename U::p_type; };
public:
using i_trait = i_typper<T, void>;
using k_trait = k_typper<T, void>;
using p_trait = p_typper<T, void>;
template<typename U = void>
typename k_typper<T, U>::type call_f() { return 0; }
};
I'll leave the second option as an exercise: (it may end up being something like:
template<typename T>
struct wrapper_traits {
....
};
template<>
struct wrapper_traits<A>{
using ....
};
template<typename T>
struct Wrapper {
....
public:
using i_trait = wrapper_traits<T>;
using k_trait = wrapper_traits<T>;
using p_trait = wrapper_traits<T>;
};
Jarod's answer is simpler. But this will work if you do not have access to std::experimental, or your company code policy forbids you...
With std::experimental::is_detected, you may do
template<typename T>
using i_type_t = typename T::i_type;
template<typename T>
struct Wrapper {
using its_i_type = typename std::experimental::detected_t<i_type_t, T>;
// would be T::i_type or std::experimental::nonesuch
};
Or to better handle case, something like:
template<typename T, bool = std::experimental::is_detected<i_type_t, T>::value>
struct WrapperWithIType {
// Empty for false case.
};
template<typename T>
struct WrapperWithIType<T, true> {
using its_i_type = i_type_t<T>;
its_i_type call_f() { return 0; }
};
and then
template<typename T>
struct Wrapper : WrapperWithIType<T> {
// Common stuff
};