Related
I'm using a "traits" pattern where I have a base case expressed as a class template
template <class>
struct DoCache {
constexpr static bool value = false;
};
and I expect users to specialize for their types:
template <>
struct DoCache<MyType> {
constexpr static bool value = true;
static void write2Cache(MyType const&) { /* implementation */ }
static optional<MyType> readFromCache(string name) { /* implementation */ }
};
The typical use is to retrieve and use this as:
// Define a variable template
template <class T>
constexpr bool do_cache_v = DoCache<T>::value;
// Use the above trait in compile time branching:
if constexpr (do_cache_v<T>)
{
write2Cache(arg);
}
There's two problems I have with this code:
A user is only indirectly enforced to provide a "value" member when specializing, let alone making it the proper value (i.e. true). By indirectly I mean they'll get a bunch of compilation errors that one can only solve if they know the answer beforehand.
There's no way of "requiring" them to create the two needed methods, namely write2Cache and readFromCache, let alone having (const) correct types.
In some code-bases I've seen the considerations above being tackled by defining a generator macro like:
#define CACHABLE(Type, Writer, Reader) ...
Is there a better way to it?
Can concepts be used to restrict the way a specialization looks?
Is there a C++17 compatible way?
an answer to any of the above is appreciated
C++17: Curiously recurring template pattern
It seems like a suitable use case for CRTP:
template<typename T>
struct DoCache {
void write2Cache() {
static_cast<T*>(this)->write2Cache();
}
// ...
};
template<typename T>
void write2Cache(DoCache<T>& t) {
t.write2Cache();
}
struct MyType : DoCache<MyType>
{
void write2Cache() { /* ... */ }
};
int main() {
MyType mt{};
write2Cache(mt);
}
Instead of requiring clients to specialize a library type over their own types, you require them to implementes their own types in-terms-of (static polymorphism) the contract/facade of the library type.
C++20: Concepts
With concepts you can skip polymorphism entirely:
template<typename T>
concept DoCachable = requires(T t) {
t.write2Cache();
};
template<DoCachable T>
void write2Cache(T& t) {
t.write2Cache();
}
struct MyType {
void write2Cache() { /* ... */ }
};
struct MyBadType {};
int main() {
MyType mt{};
write2Cache(mt);
MyBadType mbt{};
write2Cache(mbt); // error: ...
// because 'MyBadType' does not satisfy 'DoCachable'
// because 't.write2Cache()' would be invalid: no member named 'write2Cache' in 'MyBadType'
}
However again placing requirements on the definition site of client type (as opposed to specialization which can be done after the fact).
Trait-based conditional dispatch to write2Cache()?
But how is the trait do_cache_v exposed this way?
C++17 approach
Since the CRTP-based approach offers an "is-a"-relationsship via inheritance, you could simply implement a trait for "is-a DoCache<T>":
#include <type_traits>
template<typename>
struct is_do_cacheable : std::false_type {};
template<typename T>
struct is_do_cacheable<DoCache<T>> : std::true_type {};
template<typename T>
constexpr bool is_do_cacheable_v{is_do_cacheable<T>::value};
// ... elsewhere
if constexpr(is_do_cacheable_v<T>) {
write2Cache(t);
}
C++20 approach
With concepts, the concept itself can be used as a trait:
if constexpr(DoCachable<T>) {
write2Cache(t);
}
You can use a concept to sanity check specializations. Here you only need to provide the correct, by name & type, methods hence the ::value member in DoCache can be deprecated:
template <class T>
concept Cacheable = requires (T const& obj) {
{ DoCache<T>::write2Cache(obj) }
-> std::same_as<void>;
{ DoCache<T>::readFromCache(std::string{}) }
-> std::same_as<std::optional<T>>;
};
Usage is similar to the trait:
if constexpr (Cacheable<MyStruct>)
and enforces proper specialization of DoCache.
Demo
The method shown above implies that a user is allowed to specialize DoCache in an improper way, resulting in a "non cacheable" type. To prevent this from happening you can:
Use defensive programming by placing a static_assert(Cacheable<MyStruct>) after the specialization.
Leverage a constexpr static value member again and enforce an all or nothing policy in specializations, i.e. either a specialization is not provided for the type, or the provided specialization contains all members as specified in the concept. This implies you'll use a trait whose template parameter is the concept.
I'm stuck with c++17 for a project, so I don't have access to designated initializers. I have a bunch of union types that I want to avoid initializing this way (because it is annoying):
MyUnionType x;
x.value = value_set_for_all_union_members;
I want to instead have this
MyUnionType x(value_set_for_all_union_members);
But I also want to avoid writing an implementation for each union I create. I know that all my union types are going to be of the following structure, each union is meant to actually represent bit a bit field, so I actually do want type pruning here, I know it is "UB" according to C++, but that is on the C++ committee, in C it is not undefined behavior, and thus all compilers that I care about will do what I want here.
union Example{
integer_type value;
custom_safe_bitfield_abstraction<...> a;
custom_safe_bitfield_abstraction<...> b;
...
};
I thought, okay, I'll just inherit the constructor, and use CRTP to extract the appropriate integer_type. Of course I can't inherit on a union directly, so instead I opted for this strategy:
struct Example : Base<Example>{
union{
integer_type value;
custom_safe_bitfield_abstraction<...> a;
custom_safe_bitfield_abstraction<...> b;
...
};
};
using an anonymous union, I should be able to use it the same exact way as before (example.value should be the value inside of union).
Then in the implementation I do the following:
template<class Derived_T>
struct Base{
using value_type = decltype(Derived_T::value);
explicit Base(value_type v){
static_cast<Derived_T*>(this)->value = v;
}
}
This however doesn't work:
error: Incomplete type 'Example' used in nested name specifier
> using value_type = decltype(Derived_T::value);
Apparently we aren't allowed to refer to a member before it has been declared. Okay... but there must be some way to extract the type data out, after all I don't care about any memory alignment or anything.
The only other thing I can think of, is include the type in the CRTP template parameter (ie Base<Derived_T, value_type>) but I want to avoid doing that. I imagine there is some method for writing a function or specifying an internal type on each derived class, I don't want to do that either (and sort of defeats the purpose of what I'm doing anyway).
Is there a way to avoid writing the constructor per class, and with out sacrificing the other code duplication minimization goals I have?
Not exactly what you asked... but you can use the fact that you can use the type of D::value inside a member function... so using SFINAE over a template contructor...
I mean, you can write something as
template <typename D>
struct Base
{
template <typename T>
static constexpr bool is_value_type ()
{ return std::is_same_v<decltype(D::value), T>; }
template <typename T, bool B = is_value_type<T>(),
std::enable_if_t<B, int> = 0>
explicit Base (T v)
{ static_cast<D*>(this)->value = v; }
};
where the template constructor is enabled only if the deduced type of the argument is of the same type of B::value.
Remember also to add the using
using Base<Example>::Base;
inside Example.
The following is a full compiling example
#include <type_traits>
template <typename D>
struct Base
{
template <typename T>
static constexpr bool is_value_type ()
{ return std::is_same_v<decltype(D::value), T>; }
template <typename T, bool B = is_value_type<T>(),
std::enable_if_t<B, int> = 0>
explicit Base (T v)
{ static_cast<D*>(this)->value = v; }
};
struct Example : Base<Example>
{
using Base<Example>::Base;
union
{
long value;
long a;
long b;
};
};
int main ()
{
//Example e0{0}; // compilation error
Example e1{1l}; // compile
//Example e2{2ll}; // compilation error
}
I tried to do the following
template <typename T>
constexpr int some_constexpr_function() {/*some macro magic*/}
struct Base
{
template <int N>
struct IntToType;
};
template <typename T>
struct Derived : Base
{
template<>
struct IntToType<some_constexpr_function<T>()>
{ using type = T; };
};
so I could do this
struct Example : Derived<Example> {}
//...
void do_something()
{
constexpr int n = some_constexpr_function<Example>();
Base::IntToType<n>::type example_object;
}
Obviously this code won't compile, but I was wondering if there was some way to get the desired result.
"some_constexpr_function" manages to give different results depending on T thanks to some macro magic.
I can't manually specialize IntToType for every possible result.
Stateful metaprogramming tricks have been found in c++ at various points, allowing for a count (in each compilation unit) of the number of times a given template was instantiated with distinct types.
Even when such tricks where legal under the current wording of the standard, the C++ committee has treated them like bugs and worked to remove them from being legal under the standard. They want template metaprogramming to be pure for various reasons, including making it easier for compilers to memoize it and similar.
As the space of types is unbounded in size and the space of constexpr ints is not, there is no function that injectively maps a type to a constexpr int. In theory a high quality hash could be used, but the amount of information available to a C++ constexpr template program about a type (without the reflection TS) isn't going to be large enough to make a meaningful hash.
It is possible to make values which can be mapped back to types. The simplest one is:
template<class T> struct tag_t { using type=T; };
template<class T> constexpr tag_t<T> tag = {};
it is sometimes useful to be able to pass around types and the like as values, and this permits that to work; in this case, the type of the value carries with it the payload.
This isn't quite what you asked for, but it might solve the underlying problem you are trying to address.
Given a bundle of of types Ts... , you can even create std::variant<tag_t<Ts>...>, which can be a constexpr variable whose value is the index into the tag_t corresponding to a type. Here we define the map between type and index by the order of Ts... elements.
template<class...Ts> using type_set = std::variant<tag_t<Ts>...>;
using my_types = type_set<int, double, char, std::string>;
template <typename T>
constexpr my_types some_constexpr_function() {return tag<T>;}
void do_something()
{
constexpr my_types n = some_constexpr_function<Example>();
std::visit( [&]( auto tag ) {
typename decltype(tag)::type example_object;
}, n );
}
bit crazy, and every type has to be supported by the visit lambda, but...
In an effort to make life a bit easier when solving a complicated PDE system, I am writing a C++ wrapper around (the relevant portion of) a C numerical library. When dealing with multiple unknowns, the library just assigns an array to each grid point and pass its pointer to your user-specified function. The user could refer to each unknown via F[0], F[1], ...
Of course, these unknowns usually have proper mathematical names, and it would be nice to be able to refer to them as such. An obvious solution is to define a struct like
template <typename T>
struct unknowns
{
T a;
T b;
T c;
T d;
};
and convert the double* to unknowns<double>* using reinterpret_cast. This does seem to work, however after reading Can I treat a struct like an array? I have been trying to find a better solution that guarantees correctness in this conversion process (and also gracefully dealing with non-scalar T -- something that I might need a bit later).
The second most obvious solution, then, is to redefine vars so that it holds T& instead, and then concoct up something like the following
template <size_t DOF>
class factory
{
private:
template <template <typename> class Target, typename T, typename... Index>
static typename std::enable_if<(sizeof...(Index) < DOF), Target<T>>::type
_do_construct(T* array, Index... index)
{
return _do_construct<Target>(array, index..., sizeof...(Index));
}
template <template <typename> class Target, typename T, typename... Index>
static typename std::enable_if<sizeof...(Index) == DOF, Target<T>>::type
_do_construct(T* array, Index... index)
{
return { array[index]... };
}
public:
template <template <typename> class Target, typename T>
static Target<T> wrap_array(T* array)
{
return _do_construct<Target>(array);
}
};
With this, I can now convert a library-provided double* f to an unknowns<double> F safely via
auto F = factory<4>::wrap_array<unknowns>(f);
which is rather nice.
What would be even better now is if I could also omit the <4>, however I couldn't figure out how to do this. Presumably it should be possible to use SFINAE to determine how many members the struct holds, but std::is_constructible doesn't seem to be able to do what I need.
Could anyone suggest how this might be possible?
Your problem is to determine at compiletime the number of members
in a template struct Target<typename T>, where Target is
a POD struct template whose members are only known to consist 0 or more T's,
and where T for your immediate needs is double.
You would like a solution that is consistent with T being not even a scalar.
This can be solved, with one minor limition, by exploiting the fact:
that struct Target<T> cannot have more members than sizeof(Target<T>). It is
true that a struct X containing bitfields could have more members that
sizeof(X), but the type of a bitfield is {unsigned|signed} int,
so the statement holds for struct Target<T>, for any T.
The minor limitation is that T be default constructible.
Since sizeof(Target<T>) is a compiletime upper limit for the number of fields
in Target<T>, we can write a recursive-SFINAE solution.
Compiletime recursion is driven down from that limit by substitution failure
based upon the unsatisfiable type of an expression that attempts to
initialize a Target<T> with too many initializers of type T: until the
substitution does not fail, and then - thanks to the POD character of Target<T> -
we know that the number of its fields is the length of the initializer
list that it has finally accepted. We need not care with what values these
speculative initializations are attempted, provided the values are of a
type convertible to T.
(We cannot, of course, just recurse up from 0 initalizers, because Target<T>
will accept any initializer list that is not too long.)
To implement such a solution we need a compiletime means of generating initializer
lists of a type I of arbitrary length, where I is convertible to T. If
I could be an integral type, then various examples of prior art for
compiletime generation of integer sequences would spring to mind (including
examples from SO C++ luminaries:
Shaub,Wakeley,
Kühll).
The snag with this line-of-low-resistance is the constraint it apparently
entails that T be constructible from an integral type I. That would not
rule out a non-scalar T, but it would very footlingly narrow the field.
The snag is only apparent, however. Since we will not care what Ts compose
our speculative initializer lists, they might as well all be same T, and
if we stipulate only that T be default-constructible, there will be no
difficulty in turning out identical ones. Then to build these initializer lists
we do not actually need T to be constructible from an integral type I.
We just need T to be constructible from some intermediate type S that is
constructible from that I. And we can simply create such an S from a
template, say, shim<U>, for U = T, with the desired properties that shim<U>(I)
is a constructor and shim<U> operator T() const returns U().
So far so good. But is a solution of greater generality now on the cards?
We have in view a way of finding the maximum length of intializer-list-of-T
that Target<T> will accept, and can thus infer the number of fields in the
template Target given our preconditions on its character. Suppose we
waived those preconditions: that Target is a template Target<T>; that
all its fields are of type T; that it is POD.
We would then still have in view a compiletine method of determining
whether any type Target is capable of being constructed with any initializer-list-of-T
of length <= an arbitrary limit M. This is likely to be more useful than
the preliminary idea (though still recheche enough).
A trivial cost of this extra generality would be that the interface of the
template solution can no longer be parameterized simply by Target and T
whenever Target is a template on T, per your problem. In that case it will
have to be parameterized by Target<T> and T. A more important penalty
would be the fact that we would now need additionally to parameterize the
template interface with that M = the limiting length within which a
initializer list for Target shall be sought. Why? Because if Target is not
POD, then sizeof(Target) is no longer an upper bound on the number
of initializers that Target might accept.
The need for such an M was just what you didn't like about your own solution.
But the more general solution can still avoid the need for it whenever
Target is POD. Since that property is detectable by
std::is_pod<Target>::value == true, the more general solution can default M
in that case to sizeof(Target) and otherwise not default it at all.
The following solution is the residue of all this. For my compiletime-integer-sequences
apparatus I have chosen to plagiarize C++ standards committee member
Daniel Krügler,
make_indices.h
#ifndef MAKE_INDICES_H
#define MAKE_INDICES_H
/* After [Daniel Krügler]
https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++.moderated/H6icuxL0NAY
*/
template<unsigned...> struct indices {};
namespace detail {
template<unsigned I, class Indices, unsigned N>
struct make_indices;
template<unsigned I, unsigned... Indices, unsigned N>
struct make_indices<I, indices<Indices...>, N>
{
typedef typename make_indices<I + 1, indices<Indices..., I>, N>::type type;
};
template<unsigned N, unsigned... Indices>
struct make_indices<N, indices<Indices...>, N>
{
typedef indices<Indices...> type;
};
} // namespace detail
template<unsigned N>
struct make_indices : detail::make_indices<0, indices<>, N> {};
#endif // EOF
Then my contribition: initializer_count.h
#ifndef INITIALIZER_COUNT_H
#define INITIALIZER_COUNT_H
#include "make_indices.h"
#include <type_traits>
namespace detail {
/* class detail::shim<U> is a convenience wrapper of U whose
sole purpose is to be constructible from unsigned and
convertible to a U.
*/
template<typename U>
struct shim
{
static_assert(std::is_default_constructible<U>::value,
"U must be default-constructible for detail::shim<U>");
explicit shim(unsigned){};
operator U () const {
return U();
}
};
} // namespace detail
/*
class initializer_count<Target,T> will export
`static const unsigned value` == the maximum length <= Size of
initializer list of T that Target will accept.
Size defaults to sizeof(Target) if Target id POD. Otherwise a static_assert
is tripped if Size is defaulted.
*/
template<
class Target,
typename T,
unsigned Size = std::is_pod<Target>::value ? sizeof(Target) : unsigned(-1)
>
struct initializer_count;
// Terminal case
template<class Target, typename T>
struct initializer_count<Target,T,0>
{
static const unsigned value = 0;
};
// Recursion case.
template<class Target, typename T, unsigned Size>
struct initializer_count
{
static_assert(Size != unsigned(-1),
"Size cannot be defaulted for non-POD "
"Target in initializer_count<Target,T,Size>");
// SFINAE success. Target can be initialized with a list of length Size
template<unsigned ...I>
static constexpr auto count(indices<I...>) ->
decltype(Target{detail::shim<T>(I)...},Size) {
return Size;
}
// SFINAE failure.
template<unsigned ...I>
static constexpr unsigned count(...) {
// Recurse to Size - 1
return initializer_count<Target,T,Size - 1>::value;
}
static const unsigned value = count(typename make_indices<Size>::type());
};
#endif // EOF
A test program (gcc 4.7.2/4.8.1, clang 3.2):
#include "initializer_count.h"
struct non_pod
{
non_pod(){}
non_pod(double a, short b)
: _a(a),_b(b){}
double _a = 42.0;
short _b = 42;
};
template <typename T>
struct five_unknowns
{
T a;
T b;
T c;
T d;
T e;
};
template <typename T>
struct one_unknown
{
T a;
};
template <typename T>
struct zero_unknowns {};
#include <iostream>
using namespace std;
int main()
{
static const unsigned initializer_max = 100;
static_assert(!std::is_pod<non_pod>::value,"");
cout << initializer_count<zero_unknowns<char>,char>::value << endl;
cout << initializer_count<one_unknown<int>,int>::value << endl;
cout << initializer_count<five_unknowns<double>,double>::value << endl;
// Need initializer_max for rest non-pod targets...
cout <<
initializer_count<five_unknowns<non_pod>,non_pod,initializer_max>::value
<< endl;
cout << initializer_count<non_pod,short,initializer_max>::value << endl;
return 0;
}
// EOF
Expected output:
0
1
5
5
2
How about another wrapper:
template <typename T, unsigned int N>
Target<T> wrap_actual_array(T const (&a)[N])
{
return factory<N>::wrap_array<unkowns>(a);
}
I need a C++ template that, given a type and an object of that type, it can make a decision based on whether the type is an integer or not, while being able to access the actual objects. I tried this
template <typename T, T &N>
struct C {
enum { Value = 0 };
};
template <int &N>
struct C<int, N> {
enum { Value = N };
};
but it doesn't work. Is there any way I can achieve something similar?
Edit
What I was trying to achieve was something like this, that would happen at compile time:
if (type is int) {
return IntWrapper<int_value>
else {
return type
}
You can actually pass pointers or references to objects in a template instantiation, like so:
struct X {
static const int Value = 5;
};
template <X *x>
struct C {
static const int Value = (*x).Value;
};
X x;
std::cout << C<&x>::Value << std::endl; // prints 5
but apparently all this accomplishes is to initialize the template by inferring x's type, and x also needs to be declared globally. No use for what I'm trying to do, which I think is not possible after all at compile time.
What you are attempting to do isn't valid C++ templating. You can't use arbitrary objects as template parameters, all you can use are types, integral literals and in certain specialised cases string literals.
Unless i misunderstand you, what you want is impossible. In your example you show an invalid use of a pointer template parameter.
template <X *x>
struct C {
static const int Value = (*x).Value;
};
That's not valid, since (*x).Value must be a constant expression for it to be able to initialize Value. Sure Value within class X would be fine as a constant expression when used as X::Value instead. But this time, it's not since it involves a pointer (references are equally invalid in constant expressions).
To sum up, you can't do this:
Magic<T, someT>::type
And expect ::type to be T if T isn't int, and IntWrapper<someT> otherwise, since T can only be an enumeration, integer, pointer or reference type. And in the latter two cases, you won't get at the "value" of anything pointed to by the pointer or referred to by the reference at compile time. If you are satisfied with that, it's easy to solve your problem and i'm not going to show you how (i suspect you already know how).
I think you have driven yourself into a situation where solving your problem has become impossible to do with the rules as given. Drive back some steps and show us the real problem you are trying to solve, when the matter still allows to solve things.
Perhaps a simple overloaded template method works in your case?
template<typename T>
void doSomething(const T& x)
{
// ...
}
void doSomething(int x)
{
// ...
}
Addition to the other posts: You don't need to use the enum {}-hack any more:
template<typename T, int val>
struct Test {
static const int Value = 0;
};
template <int val>
struct Test<int, val> {
static const int Value = val;
};
int main(int argc,char *argv[]) {
const int v = Test<int,1>::Value;
}
template <typename T> struct A
{
enum { Value = false };
};
template <> struct A<int>
{
enum { Value = true };
};
How about this then:
template <typename T> struct A
{
T value_;
A() : value() {}
enum { is_int = false };
};
template <> struct A<int>
{
int value_;
explicit A( int v ) : value_( v ) {}
enum { is_int = true };
};
I need a C++ template that, given a
type and an object of that type, it
can make a decision based on whether
the type is an integer or not, while
being able to access the actual
objects.
You can make decisions based on the type being an integer or not, the problem is it's impossible to declare a template with an object of any type. So the question on how to decide wether a type is an integer is moot.
Note that in all answers your original template is neatly changed to
template < typename T, int >
class C {};
instead of your
template< typename T, T >
class C {};
But while C<int, 5> is a perfectly valid declaration, this is not the case for an arbitrary type T, case in point C<float, 5.> will give a compiler error.
Can you post what you're trying to achieve exactly?
And for the record, if the second template argument is always an int, and you simply want to take its value if the type is an integer type, and 0 otherwhise, you can simply do:
#include <limits>
template< typename T, int N >
class C {
static const int Value = (std::numeric_limits<T>::is_integer) ? N : 0;
};
You can do it like this:
template<typename T, int val>
struct Test
{
enum {Value = 0};
};
template <int val>
struct Test<int, val>
{
enum {Value = val};
};
int main(int argc,char *argv[])
{
int v = Test<int,1>::Value;
}
simple fix to your code - loose the reference:
template <typename T, T N>
struct C {
enum { Value = 0 };
};
template <int N>
struct C<int, N> {
enum { Value = N };
};
using reference in a template argument is meaningless anyway because you're not actually passing the argument anywhere.
Check out Alexandrescu's Modern C++ Design. I believe chapter 2 has a correct example of what you want to do.
Template specialization can be achieved like this (code taken from www.cplusplus.com):
// template specialization
#include <iostream>
using namespace std;
// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase () {return ++element;}
};
// class template specialization:
template <>
class mycontainer <char> {
char element;
public:
mycontainer (char arg) {element=arg;}
char uppercase ()
{
if ((element>='a')&&(element<='z'))
element+='A'-'a';
return element;
}
};
int main () {
mycontainer<int> myint (7);
mycontainer<char> mychar ('j');
cout << myint.increase() << endl;
cout << mychar.uppercase() << endl;
return 0;
}
In your case you would have to replace the char by what you want in the class template specialization. Now, I am not really sure what you are trying to accomplish but I hope the example above is a good indicator to how you can do some template specialization.
What I was trying to achieve was something like this, that would happen at compile time:
if (type is int) {
return IntWrapper<int_value>
else {
return type
}
I'm not sure why you aren't using IntWrapper to begin with. Where does the need come from to wrap a compile-time integer constant into an IntWrapper, if it is int?
Otherwise it looks a bit that you are trying to instantiate templates with data that is only available at run-time.