Can't deduce template type - c++

I'm trying to pass an iterator as a template parameter to a template method, but the compiler complains that:
error C2783: 'void Test::Assert(std::vector<T>::const_iterator)':
could not deduce template argument for 'T'
The code that produces the error is:
#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert(myVec.cbegin());
return 0;
}
I'm guessing there is a simple way to make this work, since most of the std algorithms can deduce type from iterator.

The reason is that the form you have T in is a non-deduced context:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
Consider a simpler case to understand why:
struct A { using type = int; };
struct B { using type = int; };
struct C { using type = int; };
template <typename T>
void Assert(typename T::type it) { ... }
Assert(5);
What should T deduce as? It's impossible to determine. You'd have to explicitly provide the type... as something like Assert<A>(5).
See also What is a nondeduced context?
since most of the std algorithms can deduce type from iterator.
That's because the standard algorithms just deduce the iterator type, not the container type. For instance std::find is just:
template <class InputIt, class T>
InputIt find( InputIt first, InputIt last, const T& value );
There is no concept of "container" here at all - it's just the iterator type that needs to be deduced. That's part of the beauty of the algorithms library.
So if what you want to do is just output the contents of the iterator, the correct function would just be:
template <typename Iterator>
void Assert(Iterator it)
{
std::cout << *it << std::endl;
}
When you call Assert(myVec.cbegin()), Iterator will get deduced as std::vector<double>::const_iterator, which is exactly what you want.

The standard algorithms look like this:
template <typename Iterator>
void some_algorithm(Iterator first, Iterator last) {
// do stuff
}
If they need the type of the iterator, they can use typename std::iterator_traits<Iterator>::value_type.
What they don't do is reference a container such as vector in any way. Not all iterators come from containers.

template <typename Ite>
void Assert(Ite &&it)
{
std::cout << *std::forward<It>(it) << std::endl;
}
That's it - the standard library just parameterizes on the whole type of the iterator. In fact, anything that behaves like an iterator can be used (that's the main reason why iterators behave like pointers). This is called "duck typing".
What you are trying to do (restricting the function to only those types which are explicit iterators) is what C++17 concepts are about.

#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename T::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert<std::vector<double> >(myVec.cbegin());
return 0;
}
Try out this once.

The following code is compiled ok using clang.
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int main(int argc, char* argv[])
{
Test test;
std::vector<double> myVec;
myVec.push_back(2.0f);
test.Assert<double>(myVec.cbegin()); // call Assert in this way.
return 0;
}
The outputs:
$ ./a.out
2
The compiler's version:
$ clang++ -v
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM
3.6.0svn) Target: x86_64-apple-darwin14.1.0 Thread model: posix

Related

c++20 concepts: How can I use a type that may or may not exist?

I have begun a project that makes heavy use of c++20 concepts as a way of learning some of the new c++20 features. As part of it, I have a function template that takes a single argument and operates on it. I wish to have the flexibility to pass types to this function that specify another type that they operate on, but that defaults to something else if that specification doesn't exist.
For example, here is a type that specifies a type that it operates on:
struct has_typedef_t
{
typedef int my_type; //operates on this type
void use_data(const my_type& data) const
{
//do something else
}
};
and one that does not specify a type, but operates on a default type specified elsewhere:
typedef std::string default_type;
struct has_no_typedef_t
{
void use_data(const default_type& data) const
{
//do something
}
};
I have a simple concept that can tell me if any given type has this specification:
template <class T> concept has_type = requires(T t) {typename T::my_type;};
And the function might look something like the following:
template <class T> void my_function(const T& t)
{
//Here I want a default-constructed value of the default
//type if the argument doesn't have a typedef
typename std::conditional<has_type<T>, typename T::my_type, default_type>::type input_data;
t.use_data(input_data);
}
The problem here is that the second template argument is invalid for anything that doesn't specify a type, e.g. has_no_typedef_t. An example program:
int main(int argc, char** argv)
{
has_no_typedef_t s1;
has_typedef_t s2;
// my_function(s1); // doesn't compile:
//'has_no_typedef_t has no type named 'my_type'
my_function(s2); //compiles
return 0;
}
What I am looking for is a replacement for the following line:
typename std::conditional<has_type<T>, typename T::my_type, default_type>::type input_data;
as this is causing the problem. I am aware that I can pull of some tricks using an overloaded function using the concept above and combining decltype and declval, but I am looking for something clean and have not been able to come up with anything. How can I achieve this behavior cleanly?
Below is the full code for the full picture (c++20):
#include <iostream>
#include <type_traits>
#include <concepts>
#include <string>
template <class T> concept has_type = requires(T t) {typename T::my_type;};
struct has_typedef_t
{
typedef int my_type;
void use_data(const my_type& data) const
{
//do something
}
};
typedef std::string default_type;
struct has_no_typedef_t
{
void use_data(const default_type& data) const
{
//do something else
}
};
template <class T> void my_function(const T& t)
{
//Here I want a default-constructed value of the default
//type if the argument doesn't have a typedef
typename std::conditional<has_type<T>, typename T::my_type, default_type>::type input_data;
t.use_data(input_data);
}
int main(int argc, char** argv)
{
has_no_typedef_t s1;
has_typedef_t s2;
// my_function(s1); // doesn't compile:
//'has_no_typedef_t has no type named 'my_type'
my_function(s2); //compiles
return 0;
}
This has had a solution since C++98: a traits class. Concepts just makes it a bit easier to implement:
template<typename T>
struct traits
{
using type = default_type;
};
template<has_type T>
struct traits<T>
{
using type = T::my_type;
};
Without concepts, you'd need to use SFINAE to turn on/off the specializations based on whether the type has the trait or not.
You can use lambda combined with if constexpr to determine the type of the return. The type_identity here is to solve the problem that the type may not be default_initializable.
typename decltype([]{
if constexpr (requires { typename T::my_type; })
return std::type_identity<typename T::my_type>{};
else
return std::type_identity<default_type>{};
}())::type input_data;
t.use_data(input_data);
Demo

STL container as template parameter in function, error in call

Cant understand what is wrogn with code, second function definition or call of this function in main?
I think, but not sure, problem in call, cause without calling code compiles well. Compiler gcc
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void show_element(T ob)
{
cout << ob << " ";
}
template<template<class> class S, class T>
void show_sequence(S<T> sequence)
{
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
int main(int argc, char const *argv[])
{
std::vector<int> v(20, 0);
//here the problem
show_sequence<std::vector<int>, int>(v);
return 0;
}
std::vector isn't a template of one parameter, it takes an allocator type as well. You can use it as vector<T> simply because the second parameter has a default (std::allocator<T>).
As it's written, your template function cannot accept any standard container, since off the top of my head, none take just a single type parameter.
An approach that would work, and not require you to know how many template parameters a container requires, is to accept a container type (not template), and glean the value type from the container type.
template<class Seq>
void show_sequence(Seq const& sequence)
{
typedef typename Seq::value_type T;
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
All standard containers have a value_type member, so this will work with any of them. Furthermore, it will work with any container that takes its cue from the standard library.
The problem is that std::vector is a template but std::vector<int> is a type.
When you are giving the second one to the function, you are giving one type and not a template.
So, you can rewrite your function as :
template<class S>
void show_sequence(S sequence)
Moreover, vector does not take only one template paramete but two (see StoryTeller answer)
It is similar to this question: https://stackoverflow.com/a/29493191/1889040
It is because vector is template of <type, allocator>
The code should be
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void show_element(T ob)
{
cout << ob << " ";
}
template<template<class,class> class S, class T, class Allocator>
void show_sequence(S<T, Allocator> sequence)
{
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
int main(int argc, char const *argv[])
{
std::vector<int> v(20, 0);
//here problem solved
show_sequence<vector, int, allocator<int> > (v);
show_sequence(v);
return 0;
}

Getting type from template template method parameters

I'm trying to make a method that picks a random element from a container type, like std::vector. Before, I was using this:
std::string pick_random(std::vector<std::string> c) {
int r = std::rand() % ids.size() + 1;
auto it = c.begin();
std::advance(it, r);
return *it;
}
which, as far as I could tell, worked fine. That's not to say it is fine, just that it appeared to be.
I soon had to do the same thing for another container, so I tried using template template arguments to make the method generic:
template <template<typename element_t> container_t>
element_t pick_random(container_t from) { /* ... */ }
This, however, throws an error:
element_t does not name a type
I think my intent is clear enough, but to restate it: I'm trying to get the element type of the list. I could have a separate template parameter, but then it can't properly infer the type. I've tried various different versions, but none work.
container_t is not a type, container_t<T> is.
You may use the following:
template <template<typename, typename...> C, typename T, typename...Ts>
T pick_random(const C<T, Ts...>& from);
as for std::vector, you have allocator: std::vector<T, Alloc>.
In C++14, you may simply use auto
template <typename C>
auto pick_random(const C& from) { /* ... */ }
I don't think that "template template arguments" are required here,
you could simply use the value_type from the container:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <list>
template <typename T>
typename T::value_type pick_random(T& from) {
int r = std::rand() % from.size();
auto it = from.begin();
std::advance(it, r);
return *it;
}
int main() {
std::srand(std::time(0));
std::vector<std::string> words {"the", "frogurt", "is", "also", "cursed"};
std::list<int> numbers {1, 2, 3, 4, 5};
std::cout << "words: " << pick_random(words) << std::endl;
std::cout << "numbers: " << pick_random(numbers) << std::endl;
}
value_type - the type of the values that can be obtained by dereferencing the iterator.
Source: http://en.cppreference.com/w/cpp/iterator/iterator_traits
Even better would be to avoid the arbitrary restriction on class templates. After all, why not be able to pick an element from a raw array? In order to correctly name the type in C++11, we'd have to get the result of an unqualified call to begin, which we can get via:
namespace detail {
using std::begin;
template <typename C>
auto adl_begin(C&& c) -> decltype(begin(std::forward<C>(c))) {
return begin(std::forward<C>(c));
}
}
using detail::adl_begin;
And then use that to deduce the element_type from an arbitrary container:
template <typename C>
auto pick_random(C& container) -> decltype(*adl_begin(container))
{ /* rest as before */ }
Side-note: take your container by reference, not by value.
If you're only using standard library containers then you can get the stored type out of them by using container_t::value_type.
template <typename container_t>
typename container_t::value_type pick_random(container_t& container)
{ ... }

Passing iterators to class functions

I'm trying to create a new templated class "CrazyBucket< T >" which has to hold multiple values of type T.
I want to create a constructor for this class that can accept any 2 forward iterators as its arguments and copy in those values (of type T) to the class instance.
Constructor:
CrazyBucket< T >::CrazyBucket( iterator< forward_iterator_tag, T > start, iterator< forward_iterator_tag, T > end )
{ ... }
But when I try to call it with,
vector< int > vec;
vec.push_back( 4 );
CrazyBucket< int > bucket( vec.begin(), vec.end() );
I get the following error,
candidate constructor not viable: no known conversion from 'iterator' (aka '__wrap_iter<pointer>') to 'std::iterator<std::forward_iterator_tag, int>' for 1st argument
Any help with how I should define my constructor is much appreciated.
Thanks in advance.
You can use SFINAE to exclude non-matching types in a fashion I think is close to what you want.
#include <iostream>
#include <iterator>
#include <vector>
template<class T>
class CrazyBucket
{
public:
template<class It, typename = typename std::enable_if<
std::is_same< typename std::iterator_traits<It>::value_type,T>::value>::type>
CrazyBucket(It beg, It end)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
}
};
int main()
{
std::vector<int> vInt;
CrazyBucket<int> cbOK(vInt.begin(), vInt.end());
int ar[10];
CrazyBucket<int> cbAlsoOK(ar, ar+10);
// uncomment for failure test case.
//std::vector<double> vDbl;
//CrazyBucket<int> cbFail(vDbl.begin(), vDbl.end());
}
Also accomplished with a static assertion:
template<class It>
CrazyBucket(It beg, It end)
{
static_assert(std::is_same<T, typename std::iterator_traits<It>::value_type>::value,
"failed to match iterator value type");
std::cout << __PRETTY_FUNCTION__ << '\n';
}
Either is restrictive, and you should know that may not be the end goal you had in mind. For example, an iteration of short will naturally store as int without data loss, yet this kind of SFINAE will toss it. That too can be overcome with more expansion, but by that time I think you need to consider whether it is really worth it in the end.
Anyway, best of luck.
Does it really have to be the constructor? The problem as I see it is that you'd need to have a specialized constructor which isn't possible as per the standard. If you can defer your initialisation to a member function then the following approach will work:
template<class T>
struct CrazyContainer {
template<class U>
void init(U first,U last) {
for(auto it=first;it!=last;it++) {
// do stuff with 'it'
}
}
};
main() {
std::vector<int> vec;
CrazyContainer<int> f;
f.init(vec.begin(),vec.end());
}
I'm looking forward to seeing if there's someone else that can come up with a way that permits this via a constructor.
Edit:
Thanks to Sebastian for pointing out that a templated constructor will work just as well as the templated method:
template<class T>
struct CrazyContainer {
template<class U>
CrazyContainer(U first,U last) {
for(auto it=first;it!=last;it++) {
// do stuff
}
}
};
main() {
std::vector<int> v;
std::set<int> s;
CrazyContainer<int> cv(v.begin(),v.end());
CrazyContainer<int> cs(s.begin(),s.end());
}

Getting the C++ compiler to reveal what a type can be converted to

Below is a flawed (and simplified) template function that expects to work on a template arg that can be converted to one of a predefined number of types.
It happens to be 2 types, but it cold be many more.
void do_something_type_specific( const int &unused ) { std::cout << 'i'; }
void do_something_type_specific( const std::string &unused ) { std::cout << 's'; }
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
do_something_type_specific( *begin );
// Perhaps more code...
}
This happens to produce the desired results in my environment.
Template instances will compile successfully iff *Iterator produces a type that's convertible to exactly one of the choices.
However, this code unnecessarily requests that the conversion be performed and, despite unused being unused, there is still UB when begin == end.
How can this this behavior be implemented in C++03 without these problems?
Instead of dereferencing the iterator that my result in undefined behaviour when begin == end, you could try using std::iterator_traits<>. E.g.:
#include <iterator>
#include <string>
#include <cstdio>
void do_something_type_specific(std::string const&) { printf("%s\n", __PRETTY_FUNCTION__); }
void do_something_type_specific(int const&) { printf("%s\n", __PRETTY_FUNCTION__); }
template<class T>
struct ProduceValue
{
static T value;
};
template<class T>
T ProduceValue<T>::value;
// Specializations for types that can't be default constructed or must be initialized.
template<>
char* ProduceValue<char*>::value = "";
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
do_something_type_specific(ProduceValue<value_type>::value);
}
int main() {
char** p = 0;
perform_work_on_a_range(p, p);
long* q = 0;
perform_work_on_a_range(q, q);
}
Output:
void do_something_type_specific(const string&)
void do_something_type_specific(const int&)
The only inconvenience is that ProduceValue<T> has to be specialized for types that can't be default constructed or must be initialized for other reasons (like char*).
There is a boost::is_convertible metafunction that you can use to determine if a type T can be converted to some other type U.
Secondly, for begin == end, just insert a run-time check.
The problematic code in the question is trying to leverage features of both template parameters and function parameters.
Function parameters allow type conversions, but require an instantiation of the type. Template parameters don't need instantiation, but also don't perform type conversions.
The pattern below uses Boost's enable_if and is_convertible to allow template functions to be chosen by the compiler as if template parameters supported the same type conversion rules as function parameters. (Thank #dhavenith for the suggestion)
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
// enable_if_c makes the return type either void or a Substitution Failure.
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,int>::value>::type
do_something_type_specific()
{
std::cout << 'i';
}
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,std::string>::value>::type
do_something_type_specific()
{
std::cout << 's';
}
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
// This code is from #MaximYegorushkin's answer. Vote him up :)
typedef typename std::iterator_traits<Iterator>::value_type value_type;
do_something_type_specific<value_type>();
// Perhaps more code...
}
This has been verified with #MaximYegorushkin's sample main.
int main() {
char** p = 0;
perform_work_on_a_range(p, p);
long* q = 0;
perform_work_on_a_range(q, q);
}
Output:
si
You probably want to do something like this instead:
template <typename T>
void do_something_type_specific() {}
template <>
void do_something_type_specific<int>() {...}
template <typename Iterator>
void perform_work_on_a_range(Iterator begin, Iterator end) {
do_something_type_specific<typename Iterator::value_type>();
}