I have template with overloaded method. I'm trying to create pointer to the overloaded method.
template<typename T>
class Future {
public:
const T& get() const;
bool get(T*, int timeoutMs) const;
};
...
const void*&(Future<void*>::*x)()const = &Future<void*>::get;
Compilation fails with this error:
no matches converting function 'get' to type 'const void*& (class Future<void*>::*)()const'
candidates are: const T& Future<T>::get() const [with T = void*]
bool Future<T>::get(T*, int) const [with T = void*]
I have tried to typedef Future<void*> without any luck.
If T is void* the const should be on the pointer not on the pointed memory:
void* const & (Future<void*>::*x)() const = &Future<void*>::get;
Templates themselves have no pointers. A template is a template, it tells c++ how to create a class. So
template<class T>
class Container {
public:
T* element() { return element_; }
void SetElement(Element *element) { element_ = element; }
typedef void (*SetElementFunctionPointer)(Element *element);
private:
T *element_;
};
typedef Container<int> IntContainer;
The code above shows you a Container template, and how you create an integer container (IntContainer) by using the Container template. In there I've declared a typedef for a SetElementFunctionPointer.
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.
My idea is to create a template out of interface such that it can return any container:
template <class T>
class IValue {
public:
virtual I& get() const = 0;
};
template<typename T>
class Value : public IValue<T>
{
public:
Value() :m_value()
{}
virtual T& get() const override
{
return m_value;
}
virtual ~Value()
{}
private:
T m_value;
};
class A
{
public:
A() {}
};
int main()
{
Value<A> a1;
//a1.get();
}
But I get compilation error as mentioned below:
$ c++ -std=c++14 try52.cpp
try52.cpp:4:17: error: 'I' does not name a type
virtual I& get() const = 0;
^
try52.cpp: In instantiation of 'class Value<A>':
try52.cpp:32:10: required from here
try52.cpp:14:16: error: 'T& Value<T>::get() const [with T = A]' marked override, but does not override
virtual T& get() const override
^
try52.cpp: In instantiation of 'T& Value<T>::get() const [with T = A]':
try52.cpp:34:1: required from here
try52.cpp:16:16: error: invalid initialization of reference of type 'A&' from expression of type 'const A'
return m_value;
How can I design or implement such a functionality?
Thanks for the comment I got this working but is it a right design:
template <class T>
class IValue {
public:
virtual const T& get() const = 0;
};
template<typename T>
class Value : public IValue<T>
{
public:
Value() :m_value()
{}
virtual const T& get() const override
{
return m_value;
}
virtual ~Value()
{}
private:
T m_value;
};
class A
{
public:
A(){}
};
int main()
{
Value<A> a1;
a1.get();
}
After fixing your typo on line 4 (I instead of T) your compiler will tell you that it cannot convert from const T to T& at the return statement of T& get() const.
Since your get() is const-qualified, the this-pointer will point to a const object inside the function. You cannot use a non-const reference to refer to a non-mutable member of a const object.
Either don't constqualify T& get() or have it return a reference to a const T: T const& get() const.
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);
};
I've declared a template class MyContainer as bellow, then created an instance of it of type DataType1. The DataType1 class provides a friend function "DataSpecificComparison" which is used by std::sort to compare DataType1 objects. The program compiled and sorted correctly.
I then defined a class called DataType2, gave it a friend implementation of "DataSpecificComparison" and used it to create another instance of MyContainer.
I am now unable to compile the program as a "C2914: 'std::sort' : cannot deduce template argument as function argument is ambiguous" compile time error is reported.
How can a developer specify that the DataSpecificComparison binary predicate is to take arguments of template type T*? Or is there another way around this issue?
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
....
public:
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison)
}
}
class DataType1
{
....
friend bool DataSpecificComparison(const DataType1 * lhs, const DataType1 * rhs)
}
class DataType2
{
....
friend bool DataSpecificComparison(const DataType2* lhs, const DataType2* rhs)
}
You can use a temporary local function pointer variable of the required type to select the correct overload of DataSpecificComparison:
void SortMyContainerObjects()
{
typedef bool (*comparer_t)(const T*, const T*);
comparer_t cmp = &DataSpecificComparison;
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), cmp);
}
Here the compiler can deduce that you want to use the DataSpecificComparison overload that matches the comparer_t type, which resolves the ambiguity.
sth already gave a correct answer, but there's also a direct alternative based on the same principle:
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(),
static_cast<bool (*comparer_t)(const T*, const T*)>(&DataSpecificComparison));
}
This uses essentially the same mechanism. The cast forces overload resolution to happen before the Template Argument Deduction for std::sort.
template<typename T>
struct DataSpecificComp : public binary_function<T, T, bool>
{
public:
bool operator()(const T* lhs, const T* rhs)
{
return *lhs < *rhs;
}
};
call the sort function as shown below:
sort(vi.begin(), vi.end(), DataSpecificComp<int>());
I'd prefer something along the following lines: by default it compares objects with less_than (so you wouldn't have to remember to provide a function with a funny name), and there's an overload that allows giving your own comparison functor (again, value-based):
#include <vector>
#include <algorithm>
#include <functional>
template <class T, class Func>
struct indirect_binary_call_type: public std::binary_function<const T*, const T*, bool>
{
Func f;
indirect_binary_call_type(Func f): f(f) {}
bool operator()(const T* a, const T* b) const
{
return f(*a, *b);
}
};
template <class T, class Func>
indirect_binary_call_type<T, Func> indirect_binary_call(Func f)
{
return indirect_binary_call_type<T, Func>(f);
}
template <class T>
class MyContainer
{
private:
std::vector<T*> m_vMyContainerObjects;
public:
void Sort()
{
Sort(std::less<T>());
}
template <class Func>
void Sort(Func f )
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), indirect_binary_call<T>(f));
}
};
int main()
{
MyContainer<int> m;
m.Sort();
m.Sort(std::greater<int>());
}
Did you try defining DataSpecificComparison as template with bunch of specializations and giving it the type?
template<T>
bool DataSpecificComparison(const T* t1, const T* t2)
{
// something non compilable here
}
template<> bool DataSpecificComparison<Data1>(const Data1* t1, const Data1* t2)
{
// return *t1 < *t2;
}
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison<T>)
}
....
Templating DataSpecificComparison should work. You can also specifically call the proper std::sort template, but it's a bit cumbersome:
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
typedef bool (*compsT)(T, T);
public:
....
void SortMyContainerObjects()
{
std::sort<std::vector<T*>::iterator, compsT>(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison);
}
}