I am quite new to std::enable_if and wondering how to use it.
I have a template class:
template<int a, int b>
class foo {
}
Now I only want to instantiate it when a + b equals to 10.
Could I make this possible using std::enable_if?
The second question:
If I have a member in class foo
template<int a, int b>
class foo {
int c;
}
I only want to have c when
a = 5.
How do I do that using std::enable_if?
Is this one the correct case to use std::enable_if?
template<int a, int b, typename T = typename std::enable_if<a + b == 10>::type>
class foo {
};
This should do the job; just make sure you never explicitly provide the third template parameter when instantiating the template.
As others mentioned, static_assert is a much better fit.
I guess you can use static_assert better to enforce that constraint instead of enable_if
template<int a, int b>
class foo {
static_assert(a+b==10, "a+b is not 10");
};
int main()
{
foo<5,5> f; // will compile
foo<1,5> f; // will fail to compile with error: a+b is not 10
return 0;
}
enable_if is primarily used to conditionally remove functions and classes from overload resolution based on type traits and to provide separate function overloads and specializations for different type traits.
With C++20
You can achieve that simply by adding requires to the template:
template<int a, int b> requires (a + b == 10)
struct foo {
int c;
};
int main() {
foo<3, 7> ok;
// foo<3, 8> doesnt_compile;
}
The requires clause gets a constant expression that evaluates to true or false deciding thus whether to consider this as a proper match, if the requires clause is true, or ignore it otherwise.
Code: https://godbolt.org/z/yHh4Et
Simple, just don't use enable_if
template<bool Ten>
struct Base
{
int c;
};
template<>
struct Base<false>
{ };
template<int a, int b>
struct foo : Base<a+b == 10>
{
};
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;
I have a templated struct that has a variant with an extra float, like this:
template <bool HasFloat>
struct Foo {
std::vector<int> a;
float b; // Not needed if HasFloat is false
};
To save memory (yes it is significant) I'd like to omit that float if HasFloat is false. Since there is a lot of other stuff in the struct the best way would be something like this:
using B = typename std::conditional<HasFloat, float, ZeroSizedType>::type;
B b;
Except there is no such thing as a zero sized type in C++ as far as I can tell. The only exception seems to be "Flexible Array Members", so I could maybe do something like this:
using B = typename std::conditional<HasFloat, float, float[]>::type;
Except they are only supported in C99, not C++.
The standard solution to this seems to be to use inheritance, since base classes can be zero-sized, however my struct is also accessed by assembly and to make the assembly simpler it is better if the float b; is at the end of the struct rather than the beginning, and anyway that isn't guaranteed.
So this seems to leave template specialisation as the only option but my class is actually rather long and I'd like to avoid duplicating everything. Is there another solution that I'm missing?
One of my colleagues came up with a fairly nice solution. It does require copy & pasting the data members but at least I don't have to duplicate my methods.
template <bool HasFloat>
struct Foo {
struct State {
std::vector<int> a;
};
struct StateWithFloat {
std::vector<int> a;
float k;
};
using FooState = std::conditional_t<HasFloat, StateWithFloat, State>;
FooState state;
};
You could do:
struct StateWithFloat {
State state;
float k;
};
But then you have to add template functions to avoid the state.a vs state.state.a problem and copy & pasting seems easier at that point.
Also #aschepler pointed out that in C++20 you will be able to use [[no_unique_address]].
You can create a struct specializing for has float or not, and then use it in your struct forwarding the template parameter. Something like this:
template <bool HasFloat>
struct PerhapsFloat;
template <>
struct PerhapsFloat<true>
{
float b;
};
template <>
struct PerhapsFloat<false>
{
};
template <bool HasFloat>
struct Foo {
std::vector<int> a;
PerhapsFloat<HasFloat> b;
};
Here, you have a demo:
https://godbolt.org/z/7zPto9
Try to extract the specialization to a base/member class.
template <bool B>
struct Foo {};
template <>
struct Foo<true>
{
float f;
};
template <bool HasFloat>
class Bar
{
Foo<HasFloat> b;
};
class Empty {};
int main()
{
std::cout << sizeof(Bar<true>) << std::endl; // 4
std::cout << sizeof(Bar<false>) << std::endl; // 1
std::cout << sizeof(Empty) << std::endl; // 1
}
I have for following Situation:
template <class K> class A
{
public:
int a;
};
class B
{
public:
virtual void DoSomething() = 0;
};
template <class K> class C : public A<K>, public B
{
public:
virtual void DoSomething()
{
a = 3; // ***
}
};
Now this works on MSVC, however gcc tells me for the line with the 3 stars : "error: 'a' was not declared in this scope". I figured out that I can replace the line with
A::a = 3;
and it works on gcc (well mingw) as well. Do we have to add the original class name all the time to be standard conform? I thought, I only have to add it if names collide otherwise.
I'm using mingw32 (gcc) 4.8.1.
Now it makes sense...
GCC is right, and MSVC is wrong. It should not work because a is template dependent but the expression a; is not.
That is, the meaning you intend of a depends on a template argument (in your case K), but the expression that contains it does not. And since the compiler cannot be sure that the instantiation of A<K> will have a member named a, it simple assumes it does not.
There are several easy solutions, all of them involve using a template dependent expression so resolve a:
this->a = 3; //my favourite
A<K>::a = 3; //you found this one
EXAMPLE:
Let's see an example of why it should not work:
template <typename K> struct A
{
int a;
};
int a; //global variable to make things more interesting
template <typename K> struct B : A<K>
{
void foo()
{
a = 3; //does it refer to A<K>::a or ::a?
}
};
//template specialization of A<int>
template <> struct A<int>
{
};
B<float> bf; // what does bf.foo() do?
B<int> bi; //and bi.foo()?
Also, you can make the opposite situation:
template <typename K> struct A
{
};
int a; //global variable to make things more interesting
template <typename K> struct B : A<K>
{
void foo()
{
a = 3; //does it refer to A<K>::a or ::a?
}
};
//template specialization of A<int>
template <> struct A<int>
{
int a; //now the member variable is in the specialization
};
B<float> bf; // what does bf.foo() do?
B<int> bi; //and bi.foo()?
As you can see, the standard C++ behavior is there for you protection, so that the code you write in a template will always refer -more or less- to the same things:
a: will be always the non template (global in the example) variable, if available. If not, it is a compiler error.
this->a: will be always the member variable, if available. If not, a compiler error.
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*)
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.