The minimal code below gives me a compile error:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
{
}
int main(int argc, char *argv[])
{
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
return 0;
}
The error is:
foo.cc: In function ‘int main(int, char**)’:
foo.cc:13:69: error: no matching function for call to ‘print_action(std::function<std::basic_string<char>*(unsigned char, std::basic_string<char>)>)’
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
^
foo.cc:13:69: note: candidate is:
foo.cc:7:6: note: template<class ActionType, class ... Cols> void print_action(std::function<ActionType*(Cols ..., ActionType)>)
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
^
foo.cc:7:6: note: template argument deduction/substitution failed:
foo.cc:13:69: note: mismatched types ‘std::basic_string<char>’ and ‘unsigned char’
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
^
foo.cc:13:69: note: ‘std::function<std::basic_string<char>*(unsigned char, std::basic_string<char>)>’ is not derived from ‘std::function<std::basic_string<char>*(Cols ..., std::basic_string<char>)>’
I also try to change the input parameter to a simple pointer function by below code:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
void print_action(ActionType*(*action_factory)(Cols..., ActionType))
{
}
string* foo_factory(uint8_t cols, string act)
{
}
int main(int argc, char *argv[])
{
print_action<string, uint8_t>(foo_factory);
return 0;
}
It gives me the same error. After some works my last guess is that it is a bug of g++ because if I change the variadic template parameter to a simple parameter no errors happen.
Am I right or I missed some syntax of c++?
I use g++-4.8.4 with c++11 flag(I checked it using clang-3.4 and g++-4.9.2).
EDIT:
If I change the code to this:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
struct Foo
{
Foo()
{}
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
{
}
};
int main(int argc, char *argv[])
{
Foo<string, uint8_t> f;
f.print_action(function<string*(uint8_t, string)>());
return 0;
}
I get no error. I don`t understand this behavior because in both situations I defined the template parameters explicitly and I did not expect any deduction, but It seems that compiler does some deduction when it is a template function but not when it is a member function of a template class.
The issue is that you have (Cols..., ActionType). One might think that the compiler should notice that Cols... should be all the arguments before the end so long as the end is the same as ActionType, but this is not how the language works.
A simple solution would to just deduce the entire argument list. Compilation will fail anyway if you happen to use the final argument as in a way the type doesn't support, and you could always add in a static_assert to ensure that the final parameter is the same as ActionType if you really wanted.
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(Cols...)> action_factory)
{
//Maybe with a static_assert like this
using LastArg = typename std::tuple_element<
sizeof...(Cols)-1, //number of args - 1
std::tuple<Cols...>
>::type;
static_assert(std::is_same<LastArg, ActionType>::value,
"The final argument must be the same type as ActionType");
}
Live Demo
Usually variadic templates are written thus
template<typename First, typename... Rest> class test;
The compiler matches the first argument and leaves the rest (empty or more) to variadic part. The behaviour when reversed is not as expected. Variadic template arguments are greedy, in that, all arguments are eaten-up by it, leaving none to the last.
Your example code compiles fine, when the order is reversed:
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(ActionType, Cols...)>) {
}
int main()
{
print_action(function<string*(string, uint8_t)>());
}
Live example.
There's a difference between argument type deduction and instantiation. Quote from C++ Templates: The Complete Guide:
The process of replacing template parameters by concrete types is called instantiation. It results in an instance of a template.
When a function template is instantiated, we get a function out of it; same for class/struct.
It seems that compiler does some deduction when it is a template function but not when it is a member function of a template class.
There is no type deduction or instantiation happening for the function call. It is not a function template, but just a function. The call is just another ordinary function call.
However, the struct is really a struct template and a struct is created out of the template, when an object was created. For this struct template instantiation
template<typename ActionType, typename... Cols>
struct Foo;
the order is correct (the variadic argument is the last) and so it works.
Related
Is there any way to construct this code so that I do not have to specify the template parameter of bar?
i.e. it does not currently compile, but will compile if I change bar(v) to bar<int>(v) in main.
#include <cstdlib>
#include <vector>
template <class T>
struct foo
{
foo(std::vector<T>& v)
{
}
};
template <class T>
void bar(const foo<T>& f)
{
}
int main()
{
std::vector<int> v;
bar(v); // does not compile
bar<int>(v); // compiles but is undesirable
return EXIT_SUCCESS;
}
The compiler is only allowed one implicit conversion but you can add an overload for bar that tries to convert whatever you give it to a foo and then calls your original bar with the temporary foo (which is what would happen if two implicit conversions was allowed in your original code):
template<typename T>
void bar(T& v) {
return bar(foo(v));
}
Since the conversion constructor in foo doesn't take the argument by const&, neither can this bar overload.
I want to disable copy constructor of some template class conditionally. In other words, I want disable copy constructor, if base type is not copy constructible. To solve such problem (in educational purposes) I decided to write following program. (Here is link to ideone https://ideone.com/QY0NHJ) Below is source of my program:
#include <algorithm>
#include <type_traits>
using namespace std;
template <typename Data>
class Container
{
public:
typedef Container<Data> self_type;
Container():
m_data()
{
}
Container(const typename
std::enable_if<std::is_copy_constructible<Data>::value,
self_type>::type& other_data) :
m_data(other_data.m_data)
{
}
Container(self_type&& other)
{
std::swap(m_data, other.m_data);
}
private:
Data m_data;
};
class SomeData
{
public:
SomeData(){}
SomeData(const SomeData&) = delete;
};
int main()
{
Container<SomeData> container;
return 0;
}
But message from compiler really confuses me:
prog.cpp: In instantiation of ‘class Container’:
prog.cpp:41:22: required from here
prog.cpp:17:2: error: no type named ‘type’ in ‘struct std::enable_if >’
Container(const typename std::enable_if::value
As I understand it should lead to SFINAE and nothing should be arised from compiler. Where am I wrong?
As I understand it should lead to SFINAE
SFINAE means "substitution failure is not an error". You need substitution to occur in order to SFINAE out something. In this case, it is sufficient to add a default template parameter to your copy constructor:
template <typename D = Data>
Container(const typename std::enable_if<std::is_copy_constructible<D>::value,
self_type>::type& other_data) :
m_data(other_data.m_data)
{
}
live example on wandbox
Follwing short programm will run perfect with VS 2013 and reach the marked point. But in XCode the compiler will show an error due ambiguous constructor. How to work around?
#include <iostream>
#include <string>
class atest
{
public:
explicit operator const char *()
{
return "";
}
template<class T> operator T()
{
}
operator std::string()
{
return std::string("Huhuhu");
}
template<class T> atest &operator =(T value)
{
}
atest &operator =(const std::string &value)
{
return *this; // I want to reach this point
}
};
int main(int argc, char* argv[])
{
atest tst;
// auto a = (std::string)tst;
std::string astr;
// do some stuff
astr=tst; // I wanna keep this line
return 0;
}
Clang is not able to distinguish between different constructor where VS2013 is taking the right one. I search now for a way to exclude the "const char *" template of the assignment operator.
std::string have multiple constructors taking single arguments, and since you provide both a conversion operator for std::string and a generic any-type conversion operator, the compiler simply don't know which constructor to pick.
I think you have written far too many overloaded functions. The only function you need is this:
operator std::string()
{
return std::string("Huhuhu");
}
Comment rest all and your code would work just fine.
I broke down a problem I already tried to explain here in following problem:
#include <iostream>
#include <string>
class atest
{
public:
operator std::string()
{
return std::string("Huhuhu");
}
operator int()
{
return 42;
}
};
int main(int argc, char* argv[])
{
atest tst;
std::string astr;
astr=tst;
int i=0;
i=tst;
return 0;
}
std::string seems to have several constructors which even cover int. I got a class which need to be cast able to std::string but also to an integral type. As the assign (=) operator is not overide able outside a class definition I got no Idea how to get the above program running.
It is bad design but it is worth noting that VS2013 has no problem with above code.
You can use explicit conversion
explicit operator std::string()
~~~~~~~
{
return std::string("Huhuhu");
}
I've been trying to figure out this problem for a couple days now and finally figured it out after striping everything down to the code below. You'll see in the code below three different attempts at a constructor for const_iterator, along with the errors I get on two of them. It appears to me that the compiler is trying to use std::iterator instead of the locally declared mine::iterator. Is it supposed to be that way?
Other tidbits that have given clues:
If I name mine::iterator something else, like mine::B, then const_iterator(const B &rhs) works.
If I derive const_iterator from a class other than std::iterator, then const_iterator(const iterator<T> &rhs) works.
Thanks for any info. Here's the code:
#include "stdafx.h"
#include <iterator>
namespace mine
{
template <class T>
class iterator : public std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, T*, T&>
{
public:
iterator() {}
};
template <class T>
class const_iterator : public std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, const T*, const T&>
{
public:
const_iterator() {}
const_iterator(const mine::iterator<T> &rhs) {} // works
//const_iterator(const iterator &rhs) {} // error C2440: initializing: cannot convert from 'mine::iterator<T>' to 'mine::const_iterator<T>'
//const_iterator(const iterator<T> &rhs) {} // error C2976: std::iterator: too few template arguments
};
}// namespace mine
using namespace mine;
int _tmain(int argc, _TCHAR* argv[])
{
iterator<int> y;
const_iterator<int> x = y;
return 0;
}
First of all 'using namespace' is evil, use typedef for ease of use. for example instead of saying iterator use mine::iterator.
Also your second point gives the answer of your question. "If I derive const_iterator from a class other than std::iterator, then const_iterator(const iterator<T> &rhs) works."
Here the nearest iterator belongs to std not mine, as std::iterator is the base class of your const_iterator.