I had a question to do with writing a range based constructor for a class but couldn't find the right phrasing to search for help on google.
Suppose I am writing a simple class, like vector, which involves having a range based constructor that inserts elements from the range into the current container:
// foo.h
#ifndef FOO_H
#define FOO_H
#include <iostream>
class Foo {
public:
Foo() {
std::cout << "Default constructor called" << std::endl;
}
template<class InputIterator> Foo(InputIterator first, InputIterator last) {
std::cout << "Range based constructor called" << std::endl;
}
Foo(size_t n, int val) {
std::cout << "size_t, int constructor called" << std::endl;
}
};
#endif // FOO_H
and have a cpp file
#include <iostream>
#include <vector>
#include "foo.h"
using std::cout; using std::endl;
int main() {
std::vector<int> v(10, 5);
Foo f_default;
Foo f_range(v.begin(), v.end());
Foo f_int(314, 159); // want this to call size_t, int ctctr
return 0;
}
In the third line in main, we create a Foo f_int(314, 159) which intuitively we want to call the size_t, int constructor. However it is matching the generic template constructor for ranges instead. Is there a way issues like this are addressed in C++? I feel like I am incorrectly dealing with writing range based constructors.
I can imagine you can use template specialization maybe, but don't really see how.
An example where such a situation might happen is if we are writing a vector class where there is a constructor based on a size_t and default value (which would be templatised on the class but I simplified here) and another constructor based on iterator ranges.
The constructor template is a better match in the third case because you're passing two int arguments, while the Foo(size_t n, int val) requires an int to size_t conversion for the first argument. If you modify your code to
Foo f_int(static_cast<size_t>(314), 159);
the constructor you want is called. But of course, this is not a good solution because it's easy to accidentally call the wrong constructor. Instead, you can use SFINAE to drop the constructor template from the overload resolution set by ensuring the argument types are iterators.
template<class InputIterator,
class = std::enable_if_t<
std::is_base_of<
std::input_iterator_tag,
typename std::iterator_traits<InputIterator>::iterator_category
>{}
>
>
Foo(InputIterator first, InputIterator last) {
std::cout << "Range based constructor called" << std::endl;
}
If you look at the table here, all iterators you can read from are InputIterators or derived types. So the code above is checking that the InputIterator type being passed to the constructor is of that type or something derived from that type.
Related
#include <iostream>
template<typename _OutType, typename _InType>
struct ConvertClass
{
_OutType operator()(_InType src)
{
return _OutType(src);
}
};
class OutClass
{
public:
OutClass(std::string str)
{
std::cout << "construct function works well!" << std::endl;
}
};
int main()
{
ConvertClass<OutClass, int>()(20); // this is wrong, because the OutClass only have one construct which takes the std::string type parameter.
// ConvertClass<OutClass, std::string>()(std::string("Hello!"));
/*
if (...) // So I wonder if there is any way that we can know whether the construct function is exists or not before we call the OutClass(int i) function
{
std::cout << "there is no such construct function of OutClass to take that parameter type" << std::endl;
return -1;
}
else
{
std::cout << "construct function works well!" << std::endl;
return 0;
}
*/
}
My Problem:
I know the main function is definitely wrong for the OutClass don't have the construct function OutClass(string str).
I wonder if there is a way only to change the Comment 1 section, the template class to make this file be compiled and linked successfully.
My English is not good, hoping you guys don't mind!
Thank you !
to my knowledge there is not runtime checking if given class is constructible using argument of given type
as said in my previous answer you can resort to Concepts and check the types at compiletime, but if clause does not work at compile time
To me it looks like the best solution would be indeed making a template class out of OutClass, then you have a single class with serves diverse purposes, dependent on you needs
one more edit to your code, I see that you pass the _OutType and _InType to your template.
In the setting where we have the following class template
template<class srcType>
class OutType:{
srcType src;
public:
OutType(srcType src) : src(src) {std::cout << "constructor works well!" << std::endl;}
}
then while invoking the class ConvertClass:
auto val = ConvertClass<OutClass<std::string>, std::string>()(std::string("Hello!"));
and also this will work:
auto val = ConvertClass<OutClass<int>, int>(20);
however, since operator() is not a static method you need first to construct object of class ConvertClass
In c++20 or even in c++17 you can in fact check if OutClass is constructible from int:
so your if clause should look like this
if(std::is_constructible<OutClass, int>::value) {
std::cout << "all is well" << std::endl;
}else{
std::cout << "you can't construct OutClass from int" << std::endl;
}
you can make the the following class template from the OutClass
template<class SrcType>
class OutClass {
SrcType src;
public:
OutClass(SrcType src) : src(src) {}
}
then in your code
return OutType<InType>(src);
if you need to check what the classes passed as template arguments actually can do (if they are arithmetic or additive or copy constructible e.g.) use Concepts from the C++20 standard
I am trying to learn and write a self custom allocator - I was expecting that the cout statement should be printed but it never does - what is the wrong am I doing - how to write custom allocator:
#include <iostream>
#include <vector>
template < class T >
class MyAllocator : public std::allocator<T> {
public:
T* allocate(size_t size)
{
std::cout << "Allocation request size " << size << std::endl;
return new T[size];
}
};
int main()
{
std::vector <int, MyAllocator<int>> x;
x.push_back(10);
x.push_back(10);
x.push_back(10);
for (auto& var : x)
std::cout << "Value " << var << std::endl;
}
Output
Value 10
Value 10
Value 10
The inheritance of the standard allocator is not needed. Remove the inheritance : public std::allocator<T> and the compiler will be kind to inform you about what you missed to implement. Until C++17 the method construct must be implemented and it is used in std::vector, not allocate. Also value_type, deallocator and destroy are missing.
template< class U, class... Args >
void construct( U* p, Args&&... args );
Since you haven't implemented it and your allocator inherits the standard allocator, std::allocator::construct is called, that does not produce output.
Why you should not inherit std::allocator
The answer on this question is simple on the one hand and not simple in practice on the other hand.
Like other classes in C++ standard library, std::allocator does not have a virtual destructor, so it should not be inherited, if it is not explicitly indicated like in std::enable_shared_from_this.
Standard containers don't use class Allocator directly. They use std::allocator_traits. It helps to implement minimal user-defined allocators. If you implement only value_type, allocate and deallocate members of MyAllocator, std::allocator_traits<MyAllocator> makes MyAllocator fully conformed to C++ named requirements: Allocator.
Let look at your MyAllocator carefully. It inherits std::allocator and "replaces" std::allocator::allocate (2).
Let read std::allocator_traits::allocate (2) reference manual, that is called by std::vector:
Calls a.allocate(n, hint) if possible. If not possible (e.g. a has no two-argument member function allocate()), calls a.allocate(n).
What you have reached. You have implemented MyAllocator::allocate(std::size_t n) (2), but not MyAllocator::allocate(std::size_t n, const void* hint) (1), it is inherited from std::allocator. It is called from std::vector, that is not what you expected. If you had not inherited std::allocator, your implementation MyAllocator::allocate would be called.
You're half way there. As described here, the standard describes custom allocator classes having several optional and required named attributes and methods. If you want your example to work, at least you must implement the required ones. These are:
add a value_type.
add an allocate(n) method. Takes a size_t input and returns an address.
add a deallocate(p, n) method. Takes two inputs and has no output.
You must also remove the inheritance to std::allocator (see #S.M.'s answer). Example similar to your MyAllocator class:
#include <iostream>
#include <vector>
#include <cstdlib>
template < class T >
class MyAllocator
{
public:
T * allocate(size_t size)
{
std::cout << "Allocation request size => " << size << std::endl;
return new T[size];
}
void deallocate(T * p_t, size_t n)
{
std::free(p_t);
}
using value_type = T;
};
int main()
{
std::vector <int, MyAllocator<int>> x;
x.push_back(10);
x.push_back(10);
x.push_back(10);
for (auto& var : x)
std::cout << "Value " << var << std::endl;
}
The problem I tried to tackle today is the one where you want to return a reference, but you actually can't because in some specific case you return something 'empty'. Just to clarify, something like this:
std::array<std::string, 5> cStrings /* do something to init */
const std::string& get_my_string(/* args */) {
if(i_know_what_to_return()) {
/*
* returning happily something in
* cStrings if I know what
*/
} else {
/* oeps... i need to return something, I don't have :-( */
return std::string(); // DON'T TRY THIS AT HOME!
}
}
I was wondering if there is not a generic approach to avoid the creation of empty objects all over the place, or, even worse, start returning copies of the objects. So I was wondering if I could not create some sort of template class that allows me to tell the compiler to manage this for me. This was my approach (although its only one of many, all with a small variation in the template declaration since this produces an error)
template<typename T, decltype(T) V>
struct empty_reference {
using type = T;
static const T static_object_;
operator T&() const {
return static_object_;
}
};
template<typename T, decltype(T) V>
const typename empty_reference<T, V>::type
empty_reference<T, V>::static_object_ = V;
unfortunately, this does not work (I get an error on 'decltype(T) V' saying 'decltype expects an expression not a type'), but I guess this is mainly because I am missing something in the template declaration.
In the end I am hoping to use this class by returning
return empty_reference<std::string, std::string()>();
So I have three questions here;
could this be possible
how do I make this work, what should I turn 'decltype(T) V' into to tell the compiler that V should be of type T while still being evaluated during compilation?
and is this a good approach or is there an easier/better solution to this problem?
Not exactly the same, but you can get your string as a function parameter instead of as a return value and rely on the fact that temporaries bind to const references.
As an example:
#include <string>
#include <iostream>
#include <utility>
struct S {
template<typename F>
void get(bool b, F &&f) {
std::forward<F>(f)(b ? s : "");
}
std::string s{"foo"};
};
int main() {
S s;
s.get(true, [](const auto &str) { std::cout << str << std::endl; });
s.get(false, [](const auto &str) { std::cout << str << std::endl; });
}
This can be a valid alternative if libraries like Boost are not already part of your project and you don't want to include them.
Otherwise, as others have mentioned, you can pick up an upcoming utility called std::optional and combine it with std::reference_wrapper as it follows:
#include <string>
#include <iostream>
#include <experimental/optional>
#include <functional>
struct S {
std::experimental::optional<std::reference_wrapper<std::string>> get(bool b) {
return b ? std::ref(s) : std::experimental::optional<std::reference_wrapper<std::string>>{};
}
std::string s{"foo"};
};
int main() {
S s;
auto opt1 = s.get(true);
std::cout << (opt1 ? opt1->get() : "-") << std::endl;
auto opt2 = s.get(false);
std::cout << (opt2 ? opt2->get() : "-") << std::endl;
}
Pretty ugly indeed. Note that a std::optional should be verified through its operator bool or the member method has_value to be sure that it contains a value.
Unfortunately you cannot use directly a std::reference_wrapper as return value, for it cannot be (let me say) _empty). In other terms, if you want to construct such an object, you must pass a valid reference to its constructor.
Another approach would be by using a template class like the following one:
#include <string>
#include <type_traits>
#include <iostream>
template<typename T>
struct defval {
static const std::decay_t<T> value;
};
template<typename T>
const std::decay_t<T> defval<T>::value = T{};
struct S {
const std::string & get(bool b) {
return b ? str : defval<std::string>::value;
}
std::string str{"foo"};
};
int main() {
S s;
std::cout << s.get(true) << std::endl;
std::cout << s.get(false) << std::endl;
}
Note that you must specialize it for those types that are not default constructible.
References must be bound to an object. So you can't return a reference in your case. Your options are:
Return a (non-owning) pointer.
Return something like boost::optional, which can hold a reference (unlike the soon to be added std::optional).
So at some point I figured it out, at least I guess.
template<typename T>
struct empty_reference {
using type = T;
static const type static_object_;
operator const type&() {
return static_object_;
}
};
template<typename T>
const typename empty_reference<T>::type
empty_reference<T>::static_object_ = {};
The concept is that the compiler will 'generate' one static 'static_object_' member for all types you use it for. Therefore, for any type you used the empty_reference for, a static object is generated in your application and returned when they are requested (i.e. if you return empty_reference<int> in two different files, a reference to the same int value will be returned).
The key was to remove the 'decltype(T) V' completely and use the universal initialization (i.e. {}) to make sure that any 'empty' constructor is called to initialize the object.
The downside is the reference needs to be constant (otherwise you can edit your 'empty reference') and the type is required to be constructable using an empty constructor.
So I guess the only question remaining is whether it is a good idea (I am not going to just my own ideas). Happy to receive any other suggestions/feedback :-)
I'm trying to implement a C++ program that, given a list of elements, prints out unique elements from the list.
I know C a lot better than C++, but I am starting out on C++ practically (coding) only now.
I've only read up on C++ concepts what templates are and I'm comfortable with function templates but I just read up on class templates and I think I'm getting confused as to where to use which one, as applied to the scenario below.
Here's what I've written so far (*note that the function isUnique is supposed to be doing something else but I'm writing just verifiable actions inside it for now):
cppArrays.h
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
template <class T> class cpparray{
private:
int size;
vector<T> elems;
public:
cpparray(int);
~ cpparray();
int isUnique(T arr);
};
template <class T> cpparray<T>::cpparray(int size)
{
vector<T> elems(size);
cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
template <class T> cpparray<T>::~cpparray()
{
cout << "Object del\n" << endl;
}
template <class T> int cpparray<T>::isUnique(T arr)
{
return arr.size();
}
cppArrays.cc
#include "cppArrays.h"
int main()
{
cpparray<int> a(10) ;
//a.push_back(1);
//a.push_back(2);
//cout << a.size() << a.begin() << a.end() << endl;
int b = isUnique(a);
return 0;
}
Details:
[1] I'm trying to use templates, because I want my vector to be able to be instantiated with any data type - char/float/int.
[2] I realize that in using a class template, by calling
cpparray<int>a(10);
I end up declaring an object a of class "cpparray" whose type is Integer. Is this correct?
If yes, then a.push_back(1) wouldn't work because it doesn't refer to the member variable but the object itself and hence it's understandable I'll get a compile time error saying no member named push_back in cpparray.
But this is making it even more difficult for me to
[1] understand when to use class template as opposed to function template,
[2] How do I initialize this vector in the template class and work with it, given my objective?
Your constructor should use initialization list to init members,
like this:
template <class T> array<T>::array(int sz) : size(sz), elems(sz)
{
cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
What you did is to declare the vector as local in the constructor, init it to size, and the local vector was destroyed at the end of block.
Use a class template when you need a generic type that has compile-time variable properties. Template parameters can be types and constants, e.g.
template<typename T, size_t Size>
class MyArray {
T elements_[Size];
public:
MyArray() {}
// ...
};
Use a function template when wish to write a generic function that can be applied to various types/parameters:
#include <cstdio>
#include <iostream>
template<size_t BufSize, typename... Args>
int strprintf(char(&buf)[BufSize], const char* fmt, Args&&... args)
{
static_assert(BufSize > 0, "Buffer too small");
static_assert(BufSize < (1 << 31), "Buffer too large");
return snprintf(buf, BufSize, fmt, std::forward<Args>(args)...);
}
int main() {
char buf[16];
int printed = strprintf(buf, "hello world %s so long", "oversized load");
std::cout << buf << "\n";
}
http://ideone.com/SLUQX3
The above is an example of how you can replace one of those old vsnprintf forwarding printf-type functions; doing all the legwork at compile time makes it drastically more efficient.
BufSize can be deduced by the compiler because the type of buf is char[16]; it can capture the source by reference, the type is char and the array size - the template variable - is 16.
It's also possible to have a templated member function of a templated class:
template<typename T>
class Foo {
T t_;
public:
Foo() : t_() {}
Foo(const T& t) : t_(t) {}
template<typename RhsT>
bool is_same_size(const RhsT& rhs) {
return t_.size() == rhs.size();
}
};
This example will only work for instances when both T and RhsT have a size() member function, leading to the following:
Foo<vector<int>> fvi;
Foo<list<double>> fld;
fvi.is_same_size(fld); // fine
Foo<int> fi;
fvi.is_same_size(fi); // compiler error
Basically, I am implementing a container class. I need to create a method which sorts the data according to the comparator function/functor which must be passed with the sort request. Since declaration and definition of the method are in different files(.h and .cpp) using templates becomes a problem (and I don't have much experience using them). In other words, I want to make a method:
void sort(function/functor f);
and I don't know how to define the function. So, is there any solution to this problem?
If you know the signature of the function/functor to be passed[*], you can use std::function. Or boost::function if you don't have C++11. So for a comparator it would be:
void sort(std::function<bool(const Element&, const Element&)> f);
where Element is the type of the elements of the container.
Failing that you could define a class with a virtual compare function, and allow callers to derive from it with their own class. It's more work for callers, but that's exactly what std::function provides: a way for callers to not have to do that.
Two warnings:
make sure there's really a good reason for the implementation of your container not to be in the header file. All of the standard containers are implemented in header files, and that mostly works OK.
make sure there's really a good reason for you to implement a sort function. Standard containers only have sort functions where std::sort doesn't work: std::list and std::forward_list.
[*] Actually std::function doesn't require the exact same signature. You just say the types you want to call it with and the type you want to convert the return value to. So if you call it with two ints and the caller provides a function that takes two longs, then that's fine. The arguments are converted just like the function call would without any std::function.
This is generally done with templates. Like this:
#include <iostream> // For example output only.
template <typename F>
void sort(F&& pred) {
pred(123);
}
void normal_func(int v) {
std::cout << "normal_func(" << v << ")\n";
}
struct my_pred {
void operator()(int v) const {
std::cout << "my_pred(" << v << ")\n";
}
};
int main() {
sort([](int v) { std::cout << "Called lambda func with " << v << '\n'; });
sort(normal_func);
sort(my_pred());
}
If, however, templates cannot be used, then your best bet would be to use polymorphic function wrapper like std::function (or boost::function, or you can write your own simple version).
Alternatively, you can use a hardcore C-style regular function along with a void pointer where user can save their context. For example, like qsort(). Though I'd try not to go there if possible.
Here is an example using std::function:
#include <iostream> // For example output only.
#include <functional> // For std::function.
void sort(const std::function<void(int)>& pred) {
pred(123);
}
void normal_func(int v) {
std::cout << "normal_func(" << v << ")\n";
}
struct my_pred {
void operator()(int v) const {
std::cout << "my_pred(" << v << ")\n";
}
};
int main() {
sort([](int v) { std::cout << "Called lambda func with " << v << '\n'; });
sort(normal_func);
sort(my_pred());
}
Hope it helps.
You can use std::function as suggested in Steve Jessop's answer but in this case I think you should consider making your sort function a template function as in Vlad's answer. A sort function has to call the comparator many times and there will be noticeable overhead to using std::function in this situation.
The easiest solution is to use a template:
class C
{
template<typename T>
void sort(T func)
{
func(12,45); // Will compile as long as your function/functor
} // Can take two integers as parameters.
}; // NOTE: or integers can be converted into your parameters.
If you want to specify using old C notation.
typedef void (*FUNC_TYPE)(int, int); // declares a function pointer type.
// returns void takes two integers.
class C
{
void sort(FUNC_TYPE func)
{
func(12,45); // Compiles only if the function
} // matches the exact type.
};
The C++11 way
class C
{
void sort(std::function<void(int,int)> func)
{
func(12,45); // Will match any func/functor that
// will return a void and takes two
} // integers.
};