Error in template function (using Boost.Tuples) - c++

#include <list>
#include <boost/tuple/tuple.hpp>
template<class InputIterator>
void f(InputIterator it)
{
typedef boost::tuple<typename InputIterator::value_type, int> Pair;
std::list<Pair> paired;
typename std::list<Pair>::const_iterator output;
for(output=paired.begin(); output!=paired.end(); ++output)
{
output->get<1>();
}
}
I'm getting libraries with this template function. Gcc 4.1.2 (codepad.org) reports the following error:
In function 'void f(InputIterator)':
Line 12: error: expected primary-expression before ')' token
compilation terminated due to -Wfatal-errors.
Could someone more experienced with templates offer advice? Either the problem or key phrases to research myself? This has me stuck.

Because get is a function template and the type of output is dependent upon the template parameter InputIterator, you need to use the template keyword:
output->template get<1>();
The Comeau C++ Template FAQ has a good description of why this is necessary.

Related

Why do I need a 'template' keyword in a not dependent context?

I know I need a template keyword when calling a template method of a template in a depended context. This is quite clear to me.
Now, I have something like:
#include <repository/RepositoryManager.hpp>
#include <events/Manager.hpp>
#include <memory>
#include <boost/di.hpp>
namespace di = boost::di;
inline std::shared_ptr<RepositoryManager> createRepositoryManager(int p) {
(void)p;
auto injector = di::make_injector(
di::bind<events::Manager>().to<events::Manager>().in(di::singleton)
);
return injector.create<std::shared_ptr<RepositoryManager>>();
}
This compiles and works as expected but what I actually need is it to be a template but simply changing the definition like this:
template <typename Param>
inline std::shared_ptr<RepositoryManager> createRepositoryManager(Param p)
Gives me a bunch of errors:
In file included from x/main.cpp:7:0:
x/setup.hpp: In function ‘std::shared_ptr<RepositoryManager> createRepositoryManager(Param)’:
x/setup.hpp:19:53: error: expected primary-expression before ‘>’ token
di::bind<events::Manager>().to<events::Manager>().in(di::singleton)
^
x/setup.hpp:19:55: error: expected primary-expression before ‘)’ token
di::bind<events::Manager>().to<events::Manager>().in(di::singleton)
^
x/setup.hpp:21:59: error: expected primary-expression before ‘>’ token
return injector.create<std::shared_ptr<RepositoryManager>>();
^~
x/setup.hpp:21:62: error: expected primary-expression before ‘)’ token
return injector.create<std::shared_ptr<RepositoryManager>>();
^
I have figured out I can change the definition like this and all is good:
template <typename Param>
inline std::shared_ptr<RepositoryManager> createRepositoryManager(Param p) {
(void)p;
auto injector = di::make_injector(
di::bind<events::Manager>().template to<events::Manager>().in(di::singleton)
);
return injector.template create<std::shared_ptr<RepositoryManager>>();
}
I'd like, however, to understand why. The events::Manager and RepositoryManager are normal classes (complete, not templates). I don't see how I could be in a dependent context here unless there's some funny rule I do not understand.
Oh, and just out of curiosity I've tried the code below and it also compiles. I'm lost.
template <typename Param>
inline std::shared_ptr<RepositoryManager> createRepositoryManager(Param p) {
(void)p;
auto injector = di::make_injector();
return injector.create<std::shared_ptr<RepositoryManager>>();
}
Edit:
It has been marked as duplicate of: Where and why do I have to put the "template" and "typename" keywords?
Well, I've read that before asking and it still does not explain my situation (unless I'm really missing something). Neither template parameter type, nor parameter value is used here, so my understanding is I'm in an independent context and I should be able to call the templated methods just fine. So where am I wrong?

Does FC++ work with g++ 4.5.0?

FC++ is a library for functional programming in C++. I am using it on MinGW with gcc 4.5.0. When I use the more basic features, I have no problems. But one of the more advanced features is giving me a template-related error (or maybe there's just a problem with my code...couldn't be!).
Does anybody have FC++ working with 4.5.0? See anything wrong with my code?
The link text is solidly out of date, though it shows a history of issues with gcc and template specialization. The link text isn't more up to date.
Here's my code:
#include <iostream>
#include "prelude.h"
using namespace fcpp;
using namespace std;
struct TwoTimes {
template <class T>
struct Sig : public FunType<T,T> {};
template <class F>
F operator() (const F& x) const { return 2*x; };
} twoTimes;
int main(int argc, char* argv[] )
{
cout << compose(twoTimes,twoTimes)(3) << endl;
return 0;
}
The error I get is:
In file included from full.h:14:0,
from lambda.h:38,
from operator.h:29,
from function.h:23,
from reuse.h:14,
from list.h:31,
from prelude.h:32,
from y.cxx:2:
smart.h: In instantiation of 'fcpp::FunctoidTraits<TwoTimes>':
prelude.h:142:74: instantiated from 'fcpp::impl::XCompose::Sig<TwoTimes, TwoTimes>'
full.h:94:53: instantiated from 'fcpp::Full2<fcpp::impl::XCompose>::Sig<TwoTimes, TwoTimes>'
y.cxx:18:46: instantiated from here
smart.h:103:7: error: no type named 'Type' in 'struct
fcpp::impl::NeededASmartFunctoidButInsteadGot<TwoTimes, false>'
In file included from y.cxx:2:0:
prelude.h: In instantiation of 'fcpp::impl::XCompose::Sig<TwoTimes, TwoTimes>':
full.h:94:53: instantiated from 'fcpp::Full2<fcpp::impl::XCompose>::Sig<TwoTimes, TwoTimes>'
y.cxx:18:46: instantiated from here
prelude.h:142:74: error: 'fcpp::FunctoidTraits<TwoTimes>::max_args' is not a valid
template argument for type 'int' because it is a non-constant expression
In file included from lambda.h:38:0,
from operator.h:29,
from function.h:23,
from reuse.h:14,
from list.h:31,
from prelude.h:32,
from y.cxx:2:
full.h: In instantiation of 'fcpp::Full2<fcpp::impl::XCompose>::Sig<TwoTimes, TwoTimes>':
y.cxx:18:46:
instantiated from here
full.h:94:53: error: no type named 'Arg1Type' in 'struct
fcpp::impl::XCompose::Sig<TwoTimes, TwoTimes>'
y.cxx: In function 'int main(int, char**)':
y.cxx:18:46: error: no match for call to '(fcpp::Compose) (TwoTimes&, TwoTimes&)'
Well .... the links you refer to are seven years old. In dog and compiler years, that is a good lifetime.
If you want functional programming with (current) C++ compilers, maybe some of the Boost libraries may be of interest?
If the answer is still needed to this, the struct TwoTimes needs to be wrapped to work with FC++. I have worked a lot with FC++ over several years. The best thing I can do is point to here on the C2 wiki where I have discussed this:
http://c2.com/cgi/wiki?FunctoidsInCpp
Any posting there I will see.

Why do I get "Expected ;" error and "Variable not declared in scope" error?

i have following code
#include <iostream>
#include <set>
#include <string>
using namespace std;
template<class Container>
void print(const Container &c)
{
Container::const_iterator itr;
for (itr=c.begin();itr!=c.end();itr++){
cout<<*itr<< '\n';
}
}
int main(){
set<string,greater<string>>s;
s.insert("georgia");
s.insert("saqartvelo");
print(s);
return 0;
}
but errors are
reverse.cpp: In function ‘void print(const Container&)’:
reverse.cpp:9: error: expected ‘;’ before ‘itr’
reverse.cpp:10: error: ‘itr’ was not declared in this scope
reverse.cpp: In function ‘int main()’:
reverse.cpp:17: error: ‘s’ was not declared in this scope
reverse.cpp:17: error: ‘>>’ should be ‘> >’ within a nested template argument list
What might cause this and how do I solve it?
You need typename Container::const_iterator instead of Container::const_iterator.
At the point the compiler is reading your code, it doesn't know that Container has such a type (it is a so-called dependent name).
Alexandre is right about the first two errors. The last two are due to an annoying syntax limitation of C++: you need to have a space in between the two closing brackets in the template expression:
set<string,greater<string> > s;
Otherwise, C++ interprets it as the right shift >> operator.

ensure that an iterator dereferences to a certain type

I have to implement a function that takes an iterator. The iterator must dereference to a certain type, say int:
template<typename iter>
void f(iter i) {
// do something here ...
int t = *i;
// do something here ...
}
The problem with this code is that if a user calls the function like this
vector<string> v;
v.push_back("aaa");
f(v.begin());
he will see an error pointing to some place in my code, not in his code (which will be confusing to him). I want the error to be in user's code to ease debugging.
GMan already pointed to a method to solve this via compile time assertions. There is another way to do this, which I prefer (it's my favorite C++ technique). You can put constraints on function arguments in a way that the function is ignored for overload resolution if the constraints don't fit. This is quite terrific, because you can fine tune your function overloads to arbitrary conditions. Here's how:
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <vector>
template<typename Iter> typename
boost::enable_if<
boost::is_same<typename Iter::value_type,int>,
void>::type
foo(Iter it) { }
int main() {
std::vector<int> v; // this is OK
foo(v.begin());
std::vector<double> v2; // this is an error
foo(v2.begin()); }
If you compile this, you will get
b.cc: In function 'int main()':
b.cc:19:16: error: no matching function for call to 'foo(std::vector<double>::iterator)'
This is because the compiler would consider foo() only, if it's argument has a value_type type inside, which is 'int' (This is what the enable_if part means). The second call of foo() can't satisfy this constraint.
enable_if is mentioned a couple of times in SO, just search for it: https://stackoverflow.com/search?q=enable_if
You could do something like this:
#include <boost/type_traits/is_convertible.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/mpl/assert.hpp>
template <typename Iter>
void foo(Iter pIter)
{
BOOST_MPL_ASSERT_MSG(
(boost::is_convertible<BOOST_TYPEOF(*pIter), int>::value),
DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT,
(int));
// ...
}
#include <vector>
#include <string>
int main(void)
{
std::vector<std::string> v(5);
foo(v.begin());
}
Which makes the message quite visible:
error C2664: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from 'boost::mpl::failed ************(__thiscall foo::DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT::* ***********)(int)' to 'boost::mpl::assert::type'
But like James says, most compilers give plenty of information to find out what happened anyway.
Given the code in question, most compilers will refer to the point of instantiation in the diagnostic message. For the following, line 16 is the line f(v.begin());.
Microsoft Visual C++ reports:
> c:\example\main.cpp(16) : see reference to function template instantiation 'void f<std::_Vector_iterator<_Myvec>>(iter)' being compiled
1> with
1> [
1> _Myvec=std::_Vector_val<std::string,std::allocator<std::string>>,
1> iter=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>
1> ]
g++ reports:
main.cpp:16: instantiated from here
Intel C++ Compiler and Comeau both report:
detected during instantiation of
"void f(iter) [with iter=std::string *]" at line 16
You need to set a constraint on the generic type.

Academic question: typename [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why do I need to use typedef typename in g++ but not VS?
Hi, recently I accounted with a "simple problem" of porting code from VC++ to gcc/intel.
The code is compiles w/o error on VC++:
#include <vector>
using std::vector;
template <class T>
void test_vec( std::vector<T> &vec)
{
typedef std::vector<T> M;
/*==> add here typename*/ M::iterator ib=vec.begin(),ie=vec.end();
};
int main()
{
vector<double> x(100, 10);
test_vec<double>(x);
return 0;
}
then with g++ we have some unclear errors:
g++ t.cpp
t.cpp: In function 'void test_vec(std::vector<T, std::allocator<_CharT> >&)':
t.cpp:13: error: expected `;' before 'ie'
t.cpp: In function 'void test_vec(std::vector<T, std::allocator<_CharT> >&) [with T = double]':
t.cpp:18: instantiated from here
t.cpp:12: error: dependent-name 'std::M::iterator' is parsed as a non-type, but instantiation yields a type
t.cpp:12: note: say 'typename std::M::iterator' if a type is meant
If we add typename before iterator the code will compile w/o pb.
If it is possible to make a compiler which can understand the code written in the more "natural way", then for me is unclear why we should add typename? Which rules of "C++ standards"(if there are some) will be broken if we allow all compilers to use without "typename"?
kind regards
Arman.
Here is a page that explains typename.
http://msdn.microsoft.com/en-us/library/8y88s595(VS.71).aspx
This will help you..