So our C++ library lets users pass in lists of values wrapped in classes with variadic constructors so the lengths of these lists can be checked at compile time. I'm trying to add some new functionality by adding new overloaded functions. However, the 'wrong' overload is being called when I pass a zero-length array of parameters e.g. {}. The following minimal example illustrates the issue:
#include <iostream>
#include <vector>
class EmptyList
{
public:
template<typename... T>
EmptyList(T&&... vals)
{
static_assert(sizeof...(vals) == 0, "Wrong number of values");
}
std::vector<double> getValues() const { return {}; }
};
void testVector(int *a, std::vector<double> b)
{
std::cout << "Vector: A (" << a << ")" << std::endl;
}
void testVector(std::vector<double> a, std::vector<double> b)
{
std::cout << "Vector: B" << std::endl;
}
void testInitList(int *a, std::initializer_list<double> b)
{
std::cout << "Init list: A (" << a << ")" << std::endl;
}
void testInitList(std::initializer_list<double> a, std::initializer_list<double> b)
{
std::cout << "Init list: B" << std::endl;
}
void testEmptyList(int *a, const EmptyList &b)
{
std::cout << "Empty list: A (" << a << ")" << std::endl;
}
void testEmptyList(const EmptyList &a, const EmptyList &b)
{
std::cout << "Empty list: B" << std::endl;
}
int main()
{
testVector({}, {});
testInitList({}, {});
testEmptyList({}, {});
}
The output is:
Vector: A (0)
Init list: B
Empty list: A (0)
Not only does the overloading behaviour seems weird, but there seems to be some sort of compiler special case for std::initializer_list making it behave differently to both my class and std::vector. Is there any way of working around this so the function overload taking my class is chosen over the one taking the pointer?
Is there any way of working around this so the function overload taking my class is chosen over the one taking the pointer?
Not without an explicit cast. When performing implicit conversion, the conversion to pointer will always be given higher preference than to a user defined type.
Related
I have a simple program like this:
#include <iostream>
#include <string_view>
class C {
public:
void print(std::string_view v) { std::cout << "string_view: " << v << std::endl; }
void print(bool b) { std::cout << "bool: " << b << std::endl; }
};
int main(int argc, char* argv[]) {
C c;
c.print("foo");
}
When I run it, it prints bool: 1
How can I get C++ to prefer the string_view implicit conversion instead of the bool implicit conversion?
You can turn the string_view overload into a template function, and add a constraint to it so that it has a higher preference than the bool overload when it receives a type that can be converted to string_view.
#include <string_view>
class C {
public:
template<class T>
std::enable_if_t<std::is_convertible_v<const T&, std::string_view>>
print(const T& v) { std::cout << "string_view: " << std::string_view(v) << std::endl; }
void print(bool b) { std::cout << "bool: " << b << std::endl; }
};
Demo.
I have a bunch of overloaded functions to take on specific int sizes, float, double, char and std::string.
eg:
#include <cstdint>
#include <iostream>
void some_func(uint8_t& src) {
std::cout << "inside uint8_t" << std::endl;
}
void some_func(uint16_t& src) {
std::cout << "inside uint16_t" << std::endl;
}
void some_func(uint32_t& src) {
std::cout << "inside uint32_t" << std::endl;
}
void some_func(uint64_t& src) {
std::cout << "inside uint64_t" << std::endl;
}
void some_func(bool& src) {
std::cout << "inside bool" << std::endl;
}
void some_func(double& src) {
std::cout << "inside double" << std::endl;
}
void some_func(float& src) {
std::cout << "inside float" << std::endl;
}
void some_func(const char& src) {
std::cout << "inside char" << std::endl;
}
int main() {
some_func((bool)true);
some_func((double)13.4);
return 0;
}
For some reason the overloaded const char& src function is called instead of double and bool. They both have explicit function overloads written, so why is the compiler promoting? moreover double is 64bits, so how is that being coverted to char? Can I solve this with template specialization? (I need to perform specifc actions depending on the data type)
Note: I am on Visual studio 2019 compiling with std=c++17
Non-const lvalue references can't be initialized with rvalues. (bool)true; and (double)3.14 are rvalues.
The only overload with a const lvalue reference parameter (which can be initialized with rvalues) is the const char& src one, that's why it's used.
Since the type is different (char vs bool/double), a temporary char is created from the argument, and then is bound to the reference.
I have a variadic template with a variadic std::tuple as a member.
I declared the default assignment operator.
MSVC complains that the operator is deleted. I can still run the program.
It doesnt give the expected result.
So 3 Questions come to my mind:
Why is the default copy assignment operator not generated even if flagged as default?
Why can I run the programm still with the code posted?
How to declare a assignment operator for std::tuple<T...> template?
#include <string>
#include <iostream>
#include <tuple>
template<typename ...T>
class Variadic
{
public:
explicit Variadic(T... args)
:m_data{ std::move(args)... }
{
}
Variadic& operator=(const Variadic&) = default;
template<typename Type>
Type get_element() const
{
return std::get<Type>(m_data);
}
private:
std::tuple<T...> m_data{};
};
int main()
{
Variadic<int, std::string> tuple1{ 1, "a" };
Variadic<int, std::string> tuple2{ 2, "b" };
std::cout << tuple1.get_element<int>() << '\n'; // 1
std::cout << tuple1.get_element<std::string>() << '\n'; // a
std::cout << tuple2.get_element<int>() << '\n'; // 2
std::cout << tuple2.get_element<std::string>() << '\n'; // b
tuple2 = tuple1; // MSVC2017 gives warning here:
//function "Variadic<T...>::operator=(const Variadic<T...> &) [with T=<int, std::string>]"
//(declared at line 13) cannot be referenced -- it is a deleted function
// still it compiles ???
std::cin.get();
std::cout << tuple1.get_element<int>() << '\n'; // 1
std::cout << tuple1.get_element<std::string>() << '\n'; // a
std::cout << tuple2.get_element<int>() << '\n'; // expect 1 but 2 ?
std::cout << tuple2.get_element<std::string>() << '\n'; // expect b but a ?
}
I have a trivial allocator:
// alloc.h
#include <cstdlib>
#include <new>
#include <iostream>
template <class T>
struct Mallocator {
typedef T value_type;
Mallocator() {
std::cout << "default ctor is called" << std::endl;
}
template <class U> Mallocator(const Mallocator<U>&) {
std::cout << "copy ctor is called" << std::endl;
}
T* allocate(std::size_t n) {
std::cout << "Mallocator::allocate(size_t n) is called, n = " << n << " ";
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
if(T *p = static_cast<T*>(std::malloc(n*sizeof(T)))) {
std::cout << "return p = " << std::hex << (uintptr_t)p << std::dec << std::endl;
return p;
}
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t n) {
std::cout << "Mallocator::deallocate(T *p, size_t n) is called, p = " << std::hex << (uintptr_t)p << std::dec << " n = " << n << std::endl;
std::free(p);
}
};
template <class T, class U>
bool operator==(const Mallocator<T>&, const Mallocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { return false; }
And this is the client code (only one of A, B, C is used):
#include "alloc.h"
#include <vector>
#include <iostream>
using namespace std;
int main() {
Mallocator<int> a;
cout << "---instantiate---" << endl;
// vector<int, Mallocator<int>> v(a); // A
vector<int, Mallocator<int>> v{Mallocator<int>(a)}; // B
// vector<int, Mallocator<int>> v(Mallocator<int>(a)); // C
cout << "---push_back(1)---" << endl;
v.push_back(1);
cout << "---push_back(2)---" << endl;
v.push_back(2);
cout << "---push_back(3)---" << endl;
v.push_back(3);
cout << "---push_back(4)---" << endl;
v.push_back(4);
cout << "---push_back(5)---" << endl;
v.push_back(5);
cout << "---exiting---" << endl;
}
The output, no matter A or B is used, is always this:
default ctor is called
---instantiate---
---push_back(1)---
// omitted for brevity..
My question:
(1) if A is present, the allocator is just constructed once, that's understandable. But when B is present instead of A, apparently the copy constructor of Mallocator is called in B, but the output doesn't reflect this. Why?
(2) If B is present, which constructor of std::vector is called? In this reference, the only constructor that takes an initializer list doesn't look like this. And if I use C instead of B, it won't compile, and the error message of clang++ is not helping..
Eidt: I know this allocator is trivial but it is not the point of this question..
The code of "alloc.h" is adapted from here, at the end of the page.
1) Your "copy constructor" isn't one. A real copy constructor isn't a template. Every class gets a copy constructor implicitly declared if it doesn't declare one itself. Mallocator<int> doesn't declare a real copy constructor, so one gets implicitly declared and defined for you. Since your class is empty, that copy constructor does nothing and prints nothing (and, thanks to the overload resolution rules, is selected to copy the allocator over your constructor template).
2) List-initialization can call non-initializer-list constructors if no initializer-list constructor is viable. B ends up calling the same constructor as A. Your C is a case of the most-vexing-parse.
I have two classes
class MyStoreClass
{
public:
std::vector<std::unique_ptr<MyClass>> my_vec;
};
and
class MyClass
{
public:
double member1;
int member2;
};
I have a vector of around 10000 MyClasses
I would like to be able to use a function such as
template<typename T>
void MyStoreClass::output_member(T MyClass::* chosen_member)
{
std::cout << chosen_member << std::endl;
}
I'm not really sure where to go from here.
Edit: I'd like to output member from each MyClass in the vector
You forgot to describe what the function should do, so I'm assuming that you want the function to print the corresponding member of all elements of my_vec.
You need to explicitly dereference the unique_ptr in order to use the pointer-to-member dereferencing operator.
The rest is straightforward:
template<typename T>
void MyStoreClass::output_member(T MyClass::* chosen_member)
{
for (const auto& ptr: my_vec)
{
if (ptr)
std::cout << (*ptr).*chosen_member << std::endl;
else
std::cout << "[null]" << std::endl;
}
}
Continuing with the assumptions, I'm going to assume that by "standard" you mean "the pre-C++11 loop that I'm used to", since the range-based loop has been standard for quite a few years now.
template<typename T>
void MyStoreClass::output_member(T MyClass::* chosen_member)
{
for (std::vector<std::unique_ptr<MyClass>>::const_iterator i = my_vec.begin();
i != my_vec.end();
++i)
{
if (*i)
std::cout << (*i)->*chosen_member << std::endl;
else
std::cout << "[null]" << std::endl;
}
}