The following code compiles and works on G++ 4.4.0 and MS VC2008 Express.
#include <iostream>
template<typename T> struct A{
protected:
T v;
public:
const T get() const{
return v;
}
A(T v_)
:v(v_){
}
};
class B: public A<const int*>{
public:
void doSomething() const{
const int* tmp = get();
std::cout << *tmp << std::endl;
}
B(const int* p)
:A<const int*>(p){
}
};
int main(int argc, char** argv){
int a = 134;
B b(&a);
const B& c = b;
b.doSomething();
c.doSomething();
return 0;
}
However, as I understand it using A<const int*> should result in const const int* A::get() const;. And I'm pretty sure I haven't seen anything like that in real code. Is using template in such way "legal"?
If not, what are alternatives? In my code I need a template class that provides two "getter" methods (const/non-const), and can take a "const int*" as a type. Something like this:
template<typename T> struct A{
protected:
T v;
public:
const T get() const{
return v;
}
T get(){
return v;
}
A(T v_)
:v(v_){
}
};
Any ideas?
If T = const int *, then const T is const int * const.
We can translate
const int *
into
int const *
A pointer to a constant int.
When you have T=int*, what you have with const T is:
int * const
Which means, a constant pointer to a int.
So in your case with T=const int*, which is int const *, what you have with const T is:
int const * const
Which means a constant pointer to a constant int. Which is legal.
If it is not the desired behavior, you may have partial specialization, like:
template<typename T> struct A<const T>{
//here comes different implementation for the case where A template is
//initialized with a const type.
It is not an issue to have multiple const qualifiers: they just fold together.
However you are misinterpreting it, because you are not placing it correctly (and it's a shame the syntax allows it).
If you place the const after the type it qualifies you'll realize that you were reading it wrong.
A const T where T is const int* is NOT const const int* = const int*.
If you write it correctly: T const where T is int const*, then you will read it int const* const, which is a const pointer to a const int, and NOT a pointer to a const int.
It's fine to do this
struct Foo {};
typedef const Foo CFoo;
const CFoo c;
All the other answers stand about constness, if you wanted the unqualified type, you can use a little template skull-duggery..
template <typename T>
struct remove_const
{
typedef T type;
};
template <typename T>
struct remove_const<T*>
{
typedef T* type;
};
template <typename T>
struct remove_const<const T>
{
typedef T type;
};
template <typename T>
struct remove_const<const T*>
{
typedef T* type;
};
template <typename T>
void foo (T& b)
{
typename remove_const<T>::type a = b;
}
If you pass in a const pointer to foo, you'll see that a has the non-const type and therefore the assignment fails.
const int const * is legal code and means a constant pointer to a constant value. Your code probably translates to the same expression.
Related
When a pointer type is passed as argument to template parameter T, how do I declare a pointer to const type?
Both const T and T const become const pointer to type, whereas I need to declare a pointer to const type.
template<typename ValueType>
class TestClass {
public:
void TestMethod(const ValueType x) {
// When ValueType is int*,
// type of x is int * const;
// how do I declare x such that it is const int* ?
std::cout<<x;
}
};
You can create a trait that does it.
template <typename T>
struct add_inner_const { using type = const T; };
template <typename T>
struct add_inner_const<T*> { using type = const T*; };
template <typename T>
using add_inner_const_t = typename add_inner_const<T>::type;
template<typename ValueType>
class TestClass {
public:
void TestMethod(add_inner_const_t<ValueType> x) {
// When ValueType is int*, x is const int*
std::cout<<x;
}
};
This will transform int ** into int * const *, if you instead want that to be const int **, then you need a different specialisation
template <typename T>
struct add_inner_const<T*> { using type = add_inner_const_t<T>*; };
I have a templated class and I'd like to almost toggle whether things within it are const based on the template type.
pseudocode:
template<bool isConst>
Class ConstableClass
{
public:
// if isConst == true make this method const
void DoSomething() "const";
// if isConst == true make the returned smartpointer type const method const
std::unique_ptr<"const" int> operator->() "const";
private:
// if isConst == true add const at the start of the next line
"const" int foo;
}
Is this sort of thing possible?
With type-traits and SFINAE:
template <bool isConst>
class ConstableClass
{
public:
template <bool C = isConst, typename = std::enable_if_t<C>>
void DoSomething() const;
template <bool C = isConst, typename = std::enable_if_t<!C>>
void DoSomething();
template <bool C = isConst, typename = std::enable_if_t<C>>
std::unique_ptr<const int> operator->();
template <bool C = isConst, typename = std::enable_if_t<!C>>
std::unique_ptr<int> operator->();
private:
std::conditional_t<isConst, const int, int> foo{};
};
With a specialization:
template <bool isConst>
class ConstableClass
{
public:
void DoSomething() const;
std::unique_ptr<const int> operator->() const;
protected:
const int foo{};
};
template <>
class ConstableClass<false>
{
public:
void DoSomething();
std::unique_ptr<int> operator->();
protected:
int foo{};
};
With constraints in c++20:
template <bool isConst>
class ConstableClass
{
public:
void DoSomething() const requires isConst;
void DoSomething() requires not isConst;
std::unique_ptr<const int> operator->() const requires isConst;
std::unique_ptr<int> operator->() requires not isConst;
private:
std::conditional_t<isConst, const int, int> foo{};
};
The first use case is not possible. You can't make function modifiers conditional and based on some template. However, I imagine you are trying to do this because you don't want to copy&paste code between the const and regular version of a function. In that case, just write a private impl method which does the actual work and use it in the cost and non-const version of the class.
private:
int& get_impl() const {...}
public:
const int& get() const {return get_impl();}
int& get() {return get_impl();}
The rest is possible and quite simple:
std::unique_ptr<"const" int>
// we can do this by:
std::unique_ptr<std::conditional_t<isConst, const int, int>> ...
// this can be written more elegantly as
template <typename T, bool isConst>
using const_if_t = std::conditional_t<isConst, const T, T>;
std::unique_ptr<const_if_t<int, isConst>>;
Making member variables const conditionally would be pretty pointless because this already happens when you make a variable const anyways.
No, it is not possible the way you want to do it. While there is a way to manipulate member variable types and function return types, there is no way to add/remove const specifier to a method. This means you have to write 2 separate specializations of the class definition for the true and false values of the template parameter.
I have a templated class and I'd like to almost toggle whether things within it are const based on the template type. Is this sort of thing possible?
Yes, and I find specializations to be more readable (unless you have access to concepts). The example below shows, rather explicitly, the two cases.
template<bool isConst>
class ConstableClass;
template<>
class ConstableClass<false>
{
int foo;
public:
void DoSomething();
std::unique_ptr<int> operator->();
};
template<>
class ConstableClass<true>
{
int const foo;
public:
ConstableClass()
: foo{0} {} // example
void DoSomething() const;
std::unique_ptr<int const> operator->() const;
};
Keep in mind that you do need to add a constructor for the true case, as adding const to foo implicitly deletes it.
For example:
struct B{};
struct A {
const B& findB() const { /* some non trivial code */ }
// B& findB() { /* the same non trivial code */ }
B& findB() {
const A& a = *this;
const B& b = a.findB();
return const_cast<B&>(b);
}
};
The thing is I want to avoid repeating the same logic inside the constant findB and non-constant findB member function.
Yes, you can cast the object to const, call the const version, then cast the result to non-const:
return const_cast<B&>(static_cast<const A*>(this)->findB());
Casting away const is safe only when the object in question was not originally declared const. Since you are in a non-const member function, you can know this to be the case, but it depends on the implementation. Consider:
class A {
public:
A(int value) : value(value) {}
// Safe: const int -> const int&
const int& get() const {
return value;
}
// Clearly unsafe: const int -> int&
int& get() {
return const_cast<int&>(static_cast<const A*>(this)->get());
}
private:
const int value;
};
Generally speaking, my member functions are short, so the repetition is tolerable. You can sometimes factor the implementation into a private template member function and call that from both versions.
I think, that using cast here is ok, but if you definitely want to avoid it, you can use some template magic:
struct B
{
B(const B&)
{
std::cout << "oops I copied";
}
B(){}
};
struct A {
public:
A(){}
A(const A&){ std::cout << "a is copied:(\n";}
const B& findB() const { return getter(*this); }
B& findB() { return getter(*this); }
private:
template <typename T, typename V>
struct same_const
{
typedef V& type;
};
template <typename T, typename V>
struct same_const<const T, V>
{
typedef const V& type;
};
template <typename T>
static typename same_const<T,B>::type getter(T& t) { return t.b;}
B b;
};
int main()
{
A a;
const A a_const;
const B& b1 = a.findB();
B& b2 = a.findB();
const B& b3 = a_const.findB();
//B& b4 = a_const.findB();
}
How is it possible to have a templated class here called
FrontBackBuffer with template parameter TBackBufferType, TFrontBufferType
template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer{
public:
explicit FrontBackBuffer(
TBufferTypeFront const & m_front,
TBufferTypeBack const & m_back):
m_Front(m_front),
m_Back(m_back)
{
};
~FrontBackBuffer()
{};
typename std::remove_reference<
typename std::remove_pointer<TBufferTypeFront>::type
>::type & getFront(){return m_Front;} // error: invalid initialization of reference of type 'A&' from expression of type 'A*'| (here T is A)
typename std::remove_reference<
typename std::remove_pointer<TBufferTypeBack>::type
>::type & getBack(){return m_Back;}
TBufferTypeFront m_Front; ///< The front buffer
TBufferTypeBack m_Back; ///< The back buffer
};
I would like to achieve the following:
to be consistent in the code, I would prefere, to no matter what the Type inside the buffer is, to have a function getFront/Back which should always return a Reference to the buffer (either a const or a non-const depending on the type: e.g const int = T should return a const int & reference! I would like to write code like this
FrontBuffer<const int&, std::vector<int> > a;
a.getFront() = 4 //COmpile error! OK!;
a.getBack()[0] = 4;
FrontBuffer< int*, GAGAType * > b;
b.getBack() = GAGAType();
b.getFront() = int(4); // this is no ERROR, i would like to get the reference of the memory location pointet by int* ....
I would like this because I want to avoid changing the syntax if I change the buffer type from reference to pointer (where I need to dereference)
Is such a Buffer class possible to accept with all possible types (like shared_ptr)
asd
All I want is some access and it should be very performant, no copies and so on
I dont know really how to write this generic buffer? Somebody has any clue?
Thanks!!!
EDIT1 I want also to be able to assign to the dereferenced pointer:
b.getFront() = int(4); // this is no ERROR, i would like to get the reference of the memory location pointet by int* ....
Thats where my problem with traits comes in!
You need to specialize (traits technique) part of your template, like this:
template <typename T>
struct MyRefTypes {
typedef const T & Con;
typedef T& Ref;
typedef const T& CRef;
static Ref getRef(T& v) {
return v;
}
};
Update
Note the special function for returning reference - it is needed if you want to behave differently for pointers - returns references for it.
End Update
And make specialization for references and const references:
template <typename T>
struct MyRefTypes {
typedef const T & Con;
typedef T& Ref;
typedef const T& CRef;
static Ref getRef(T& v) {
return v;
}
};
//Specialization for Reference
template <typename T>
struct MyRefTypes<T&> {
typedef T & Con;
typedef T& Ref;
typedef const T& CRef;
static inline Ref getRef(T& v) {
return v;
}
};
//Specialization for const Reference
template <typename T>
struct MyRefTypes<const T&> {
typedef const T & Con;
typedef const T& Ref;
typedef const T& CRef;
static inline Ref getRef(const T& v) {
return v;
}
};
//Specialization for const
template <typename T>
struct MyRefTypes<const T> {
typedef const T & Con;
typedef const T& Ref;
typedef const T& CRef;
static inline Ref getRef(const T& v) {
return v;
}
};
Update
And this "special" specialization for pointers - so they will work as references:
//Specialization for pointers
template <typename T>
struct MyRefTypes<T*> {
typedef T* Con;
typedef T& Ref;
typedef T* const CRef; //! note this is a pointer....
static inline Ref getRef(T* v) {
return *v;
}
};
//Specialization for const pointers
template <typename T>
struct MyRefTypes<const T*> {
typedef const T* Con;
typedef const T& Ref;
typedef const T* const CRef; //! note this is a pointer....
static inline Ref getRef(const T* v) {
return *v;
}
};
((However I am not sure this specialization for pointers is a good design... ))
End Update
And usage inside your class template:
template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer{
public:
typedef typename MyRefTypes<TBufferTypeFront>::Ref TBufferTypeFrontRef;
typedef typename MyRefTypes<TBufferTypeFront>::CRef TBufferTypeFrontCRef;
typedef typename MyRefTypes<TBufferTypeFront>::Con TBufferTypeFrontCon;
typedef typename MyRefTypes<TBufferTypeBack >::Ref TBufferTypeBackRef;
typedef typename MyRefTypes<TBufferTypeBack >::CRef TBufferTypeBackCRef;
typedef typename MyRefTypes<TBufferTypeBack >::Con TBufferTypeBackCon;
explicit FrontBackBuffer(
TBufferTypeFrontCon m_front,
TBufferTypeBackCon m_back):
m_Front(m_front),
m_Back(m_back)
{
};
~FrontBackBuffer()
{};
// See here special functions from traits are used:
TBufferTypeFrontRef getFront(){return MyRefTypes<TBufferTypeFront>::getRef(m_Front); }
TBufferTypeBackRef getBack(){return MyRefTypes<TBufferTypeBack>::getRef(m_Back); }
TBufferTypeFront m_Front; ///< The front buffer
TBufferTypeBack m_Back; ///< The back buffer
};
It works as expected:
http://ideone.com/e7xfoN
I have a class template that contains two similar member functions:
template<class T>
class MyTemplate {
// other stuff, then
static T* member( T& ); //line 100
static const T* member( const T& ); //line 101
};
which I instantiate like this:
MyTemplate<int* const>
and Visual C++ 9 complains:
mytemplate.h(101) : error C2535: 'int* MyTemplate<T>::member(T &)' :
member function already defined or declared
with
[
T=int *const
]
mytemplate.h(100) : see declaration of 'MyTemplate::member'
with
[
T=int *const
]
somefile.cpp(line) : see reference to class template instantiation
'MyTemplate<T>' being compiled
with
[
T=int *const
]
I certainly need the two versions of member() - one for const reference and one for non-const reference. I guess the problem has something with top-level const qualifiers, but can't deduce how to solve it.
How do I resolve this problem so that I still have two versions of member() and the template compiles?
The explanation given by fefe is correct. Foo const& and Foo const const& will simply evaluate to the same type, hence your function overloading does not work. In case your template argument is const, I'd suggest specialisation.
Version A:
template<class T>
class MyTemplate {
static T* member( T& );
static const T* member( const T& );
};
template<class T>
class MyTemplate<T const> {
static const T* member( const T& );
};
Version B:
template<class T>
class MyTemplate_mutableImpl {
static T* member( T& );
};
template<class T>
class MyTemplate_constImpl {
static const T* member( const T& );
};
template<class T>
class MyTemplate : public MyTemplate_mutableImpl<T>, public MyTemplate_constImpl<T> {
};
template<class T>
class MyTemplate<T const> : public MyTemplate_constImpl<T const> {
};
When T is int * const, T is already const, so T& and const T& are both int * const.
Or do you mean in this case, you need your class to look like:
class MyTemplate_int_p_const{
static int * member (int *&);
static int * const member (int * const &);
};
You can add this to your main template to achieve this:
template<class T>
class MyTemplate<const T>
{
static T * member(T&);
static const T* member(const T&);
};
As a responds to the OP's comment, if you don't want to use partial specialization, you'll need type_traits. It is supported by C++0x, and for VC++9, you can use boost.
In the following code, the non_const version of member will take a dummy_type ( a pointer to member function) if T is already const. So the non_const overload would not exist.
#include <type_traits>
template<class T>
class MyTemplate {
// other stuff, then
//void dummy(void);
typedef void (*dummy_type)(void);
typedef typename std::conditional<std::is_const<T>::value, dummy_type, T>::type T_no_const;
typedef typename std::remove_const<T>::type T_remove_const;
static T_no_const* member( T_no_const& t ) //line 100
{
if (std::is_same<T, T_no_const>::value)
{
return member_portal(t);
}
else
return NULL;
}
static T_no_const* member_portal(dummy_type&){return NULL;};
static T_remove_const* member_portal(T_remove_const&);
static const T* member( const T& ); //line 101
};
int main()
{
MyTemplate<int * const> mt;
MyTemplate<int *> mtt;
return 0;
}
This is the first time that I play with type_traits. It can pass compilation under g++ 4.5.2 with C++0x enabled. But I've never run it.
Main idea is, when T is const, the non_const version of member takes a argument of an arbitrary type ( a type that is not likely to be used any where else, and to not likely to be implicitly converted to), thus the non_const version disappears. But in the way, the logic breaks in the implementation of member ( as the argument type is to be used, but is not expected). So the main logic of member is move another function of member_portal.
A simple solution would be to disable the function if T is const:
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_const.hpp>
template<class T>
class MyTemplate {
static T* member( T& );
struct Disabled {};
static const T* member(typename boost::mpl::if_<boost::is_const<T>, Disabled, const T&>::type);
};