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.
Related
So i have problem with code like this:
I have struct like this
template <int N>
struct Inner
{
enum
{
val = 2*N
};
};
And i want to achive sth like this:
int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;
cout<< v <<endl;
cout<< b <<endl;
My goal is to created "Outer" struct which takes bool or Inner<int N> and set Outer::val to Inner::val or bool
So i have created sth like this (not working):
template <bool B>
struct Outer
{
enum
{
val = B
};
};
template <Inner<int> I>
struct Outer
{
enum
{
val = I::val
};
};
Whats wrong with this and how to fix that?
(I have seen some similar questions, but still can't apply this to my problem)
There are some problems in your code.
First of all: you define two different Outer structs
template <bool B>
struct Outer
{ /* ... */ };
template <Inner<int> I>
struct Outer
{ /* ... */ };
And you can't.
If you want, you can declare an Outer struct and two specializations, but you have to decide what type of template argument Outer has to receive.
Because, looking at your desiderata,
int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;
you want pass to it a type in one case (Inner<4>) and a value in the other case. And you can't.
You have to decide if Outer receive a type or a value. Before C++17, if receive a value, you have to decide the type of the value; starting from C++17, you can declare Outer as receiving a value of a generic type (auto as type of the value).
Problem: a value of Inner<int> can't be a template parameter (but see also the Michael Kenzel's answer, that show a possible C++20 solution based on template values arguments).
So the only solution I see (before C++20) is declare Outer as receiving a type
template <typename>
struct Outer;
Then you can define a Outer specialization for Inner types
template <int N>
struct Outer<Inner<N>>
{ enum { val = Inner<N>::val }; }; // or simply enum { val = N };
For bool values, you have to wrap they in a class; I suggest (starting from C++11) the use of the standard class std::integral_constant and the definition of the following Outer specialization
template <bool B>
struct Outer<std::integral_constant<bool, B>>
{ enum { val = B }; };
The use is as follows
int v = Outer<Inner<4>>::val;
int b = Outer<std::integral_constant<bool, false>>::val;
std::cout << v << std::endl;
std::cout << b << std::endl;
You can also use std::false_type defining b
int b = Outer<std::false_type>::val;
and, starting from C++17, also std::bool_constant (a shorthand for std::integral_constant for bool values)
int b = Outer<std::bool_constant<false>>::val;
A template parameter can be either a type, a value (non-type), or a template [temp.param]. What you're trying to achieve would require your template Outer to have a parameter that can be either a type or a value. Unfortunately, this is not possible.
What you could do is wrap your bool value in a type:
template <bool b>
struct InnerBoolean
{
static constexpr bool val = b;
};
and then have one common definition for Outer
template <typename T>
struct Outer
{
enum
{
value = T::val
};
};
and then use Outer<Inner<4>> and Outer<InnerBoolean<False>>.
Rather than write your own wrapper, if you rename val to value, you can use the wrappers that the standard library provides in std::bool_constant and std::true_type and std::false_type.
While up to C++17, a non-type template parameter cannot be of class type [temp.param]/4, C++20 will lift this restriction and allow template parameters of any literal type. Thus, as long as Inner can be a literal type, you will be able to just pass a value of type Inner directly and use an auto template parameter:
struct Inner
{
int N;
constexpr Inner(int N) : N(N) {}
constexpr operator int() const { return 2*N; }
};
template <auto val>
struct Outer
{
enum
{
value = val
};
};
auto a = Outer<Inner(4)>::value;
auto c = Outer<false>::value;
can C++ template detect members of specific type? As code below,
template <typename T>
class Element {
};
template <typename T>
class Container {
public:
Container() {
// check if T has member which type is "Element<whatever>"
// how many Element<whatever>s?
// offset?
}
};
I have a template class named Container, and I want to check:
If the passed in type T has member which type is Element<whatever>?
If so, can I get how many members which type is Element<whatever>?
If so, can I get the offset to the beginning of the class?
Explain more about requirement 3:
What I want is to access these fields(if exist) when I get a piece of data which is cast by reinterpret_cast<T>
This is doable in C++20 if the T of Container<T> is an aggregate ; I use the boost::pfr library as it simplifies this idiom but it is easily reimplementable by hand (boost::pfr's source is very simple to read)
#include <boost/pfr.hpp>
template<typename T, typename Target>
auto count_members_of_type()
{
unsigned int count = 0;
boost::pfr::for_each_field<T>(T{}, [&] <typename U> (U&&) {
count += std::is_same_v<std::remove_reference_t<U>, Target>;
});
return count;
}
given
struct Foo {
Element<int> a, b;
Element<float> c;
std::string d;
};
then
count_members_of_type<Foo, Element<int>>() == 2
Running example on gcc.godbolt.org: https://gcc.godbolt.org/z/srhn8GfWb
I'm reading book C++ Templates. It mentions SFINAE(substitution failure is not an error) principal can be used to detect function type.
Code example:
template <typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename U> static One test(...);
template<typename U> static Two test(U (*)[1]); // This test overloading I cannot understand
public:
enum { Yes = sizeof(IsFunctionT<T>::test<T>(0) == 1};
enum { No = !Yes };
};
I understand its intent is to find functions which cannot be categorized as arrays, but how does it work with U (*)[1]. I have never seen this before.
In a nutshell, SFINAE works by substituting a type and not giving a hard failure if the expression is ill-formed. For example you cannot have an array of functions, so if U is a function, the substitution will fail and that overload will be discarded. Now as a comment pointed out, the code you posted alone does not cover all cases. You need additional specializations, i.e:
template<typename T>
class IsFunctionT<T&> {
public:
enum { Yes = 0 };
enum { No = !Yes };
};
template<>
class IsFunctionT<void> {
public:
enum { Yes = 0 };
enum { No = !Yes };
};
template<>
class IsFunctionT<void const> {
public:
enum { Yes = 0 };
enum { No = !Yes };
};
Which I pulled from the freely available source code from the book.
The U()[1] is an unnamed pointer to an array of 1 element. And the 0 is either treated as an int or a null pointer to an U ()[1];
The sizeof is testing the function return type, the actual result of the test function isn't used as test() is never actually called, only its return type tested.
Here is the code
#include <iostream>
template<typename T>
class IsReference {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(C*);
template<typename C> static Two test(...);
public:
enum { val = sizeof(IsReference<T>::test<T>(0)) == 1 };
enum {result = !val};
};
template < class T>
void foo(T t){
std::cout<< IsReference<T>::result << "\n";
}
class C{
public: int a;
};
int main(){
C c1;
C &c2 = c1;
foo(c1);
foo(c2);
}
The output is 0 for foo(c2) also which I don't want.
Inside foo how can I check whether T is reference type or not?
I dont want to call foo as foo<C&>(c2) i.e we don't know on which type the function is getting instantiated.
You can't. As an expression, c2 is an lvalue of type C, just like c1, so in both cases argument-dependent lookup will choose foo<C>.
You get the same result using Boost.TypeTraits.
There may be some new wizardry in C++11 to help, but (a) I don't know enough about C++11 to answer, and (b) you've tagged the question C++03 anyway.
For edited question:
I dont want to call foo as foo<C&>(c2) i.e we don't know on which type
the function is getting instantiated
It's not possible. Because, when an object or reference are passed to a function, the function is not aware whether it's an object or reference.
Here is one proposed C++11 solution (using macro);
#define FOO(X) foo<decltype(X)>(X)
Use FOO instead of foo
I think it should be
template<typename C> static One test(C&);
rather than One test(C*)
When declaring a template, I am used to having this kind of code:
template <class T>
But in this question, they used:
template <unsigned int N>
I checked that it compiles. But what does it mean? Is it a non-type parameter? And if so, how can we have a template without any type parameter?
Yes, it is a non-type parameter. You can have several kinds of template parameters
Type Parameters.
Types
Templates (only classes and alias templates, no functions or variable templates)
Non-type Parameters
Pointers
References
Integral constant expressions
What you have there is of the last kind. It's a compile time constant (so-called constant expression) and is of type integer or enumeration. After looking it up in the standard, i had to move class templates up into the types section - even though templates are not types. But they are called type-parameters for the purpose of describing those kinds nonetheless. You can have pointers (and also member pointers) and references to objects/functions that have external linkage (those that can be linked to from other object files and whose address is unique in the entire program). Examples:
Template type parameter:
template<typename T>
struct Container {
T t;
};
// pass type "long" as argument.
Container<long> test;
Template integer parameter:
template<unsigned int S>
struct Vector {
unsigned char bytes[S];
};
// pass 3 as argument.
Vector<3> test;
Template pointer parameter (passing a pointer to a function)
template<void (*F)()>
struct FunctionWrapper {
static void call_it() { F(); }
};
// pass address of function do_it as argument.
void do_it() { }
FunctionWrapper<&do_it> test;
Template reference parameter (passing an integer)
template<int &A>
struct SillyExample {
static void do_it() { A = 10; }
};
// pass flag as argument
int flag;
SillyExample<flag> test;
Template template parameter.
template<template<typename T> class AllocatePolicy>
struct Pool {
void allocate(size_t n) {
int *p = AllocatePolicy<int>::allocate(n);
}
};
// pass the template "allocator" as argument.
template<typename T>
struct allocator { static T * allocate(size_t n) { return 0; } };
Pool<allocator> test;
A template without any parameters is not possible. But a template without any explicit argument is possible - it has default arguments:
template<unsigned int SIZE = 3>
struct Vector {
unsigned char buffer[SIZE];
};
Vector<> test;
Syntactically, template<> is reserved to mark an explicit template specialization, instead of a template without parameters:
template<>
struct Vector<3> {
// alternative definition for SIZE == 3
};
It's perfectly possible to template a class on an integer rather than a type. We can assign the templated value to a variable, or otherwise manipulate it in a way we might with any other integer literal:
unsigned int x = N;
In fact, we can create algorithms which evaluate at compile time (from Wikipedia):
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
int x = Factorial<4>::value; // == 24
int y = Factorial<0>::value; // == 1
}
You templatize your class based on an 'unsigned int'.
Example:
template <unsigned int N>
class MyArray
{
public:
private:
double data[N]; // Use N as the size of the array
};
int main()
{
MyArray<2> a1;
MyArray<2> a2;
MyArray<4> b1;
a1 = a2; // OK The arrays are the same size.
a1 = b1; // FAIL because the size of the array is part of the
// template and thus the type, a1 and b1 are different types.
// Thus this is a COMPILE time failure.
}
A template class is like a macro, only a whole lot less evil.
Think of a template as a macro. The parameters to the template get substituted into a class (or function) definition, when you define a class (or function) using a template.
The difference is that the parameters have "types" and values passed are checked during compilation, like parameters to functions. The types valid are your regular C++ types, like int and char. When you instantiate a template class, you pass a value of the type you specified, and in a new copy of the template class definition this value gets substituted in wherever the parameter name was in the original definition. Just like a macro.
You can also use the "class" or "typename" types for parameters (they're really the same). With a parameter of one of these types, you may pass a type name instead of a value. Just like before, everywhere the parameter name was in the template class definition, as soon as you create a new instance, becomes whatever type you pass. This is the most common use for a template class; Everybody that knows anything about C++ templates knows how to do this.
Consider this template class example code:
#include <cstdio>
template <int I>
class foo
{
void print()
{
printf("%i", I);
}
};
int main()
{
foo<26> f;
f.print();
return 0;
}
It's functionally the same as this macro-using code:
#include <cstdio>
#define MAKE_A_FOO(I) class foo_##I \
{ \
void print() \
{ \
printf("%i", I); \
} \
};
MAKE_A_FOO(26)
int main()
{
foo_26 f;
f.print();
return 0;
}
Of course, the template version is a billion times safer and more flexible.