C++ template argument with expression - c++

I am having trouble with C++. I want to be able to put an expression inside a template as an argument. Here is my code:
#include <vector>
using namespace std;
vector< ((1>0) ? float : int) > abc() {
}
int main(void){
return 0;
}
This gives me the error:
main.cpp:11:14: error: template argument 1 is invalid
main.cpp:11:14: error: template argument 2 is invalid
main.cpp:11:15: error: expected unqualified-id before ‘{’ token
In the end I want to be able to replace 1 and 0 for whatever and also float and int for typename T and U. Why does it think there are two arguments? And how do I solve this?
(Sorry if this is a duplicate I did have a good look for solutions)

Use std::conditional:
#include <type_traits>
std::vector<std::conditional<(1 > 0), float, int>::type> abc() {}

Related

Error when calling an Integral template member function with g++ and clang++ [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 7 years ago.
I'm currently stuck on a compilation error, which I can't really identify...
Here's a minimal working example:
#include <iostream>
template <typename T, int R>
class a_type
{
public:
template <int N>
double segment()
{
return 42;
}
};
template <int M>
double func()
{
a_type<double, M> a;
return a.segment<1>();
}
int main(int argc, char *argv[])
{
std::cout << func<10>() << std::endl;
return 0;
}
The error message from GCC reads:
g++ main.cpp -o main
main.cpp: In function 'double func()':
main.cpp:18:26: error: expected primary-expression before ')' token
return a.segment<1>();
^
main.cpp: In instantiation of 'double func() [with int M = 10]':
main.cpp:23:28: required from here
main.cpp:18:22: error: invalid operands of types '<unresolved overloaded function type>' and 'int' to binary 'operator<'
return a.segment<1>();
^
Clang also says something similar:
clang++ main.cpp -o main
main.cpp:18:26: error: expected expression
return a.segment<1>();
^
So based on GCC's error message, 'a.segment' is a member function call missing the parentheses, which obviously gets rejected. But that does not make sense at all, since I don't see any reason for treating that expression as such.
Moreover, if I change M to any integral number on line 17, like so:
#include <iostream>
template <typename T, int R>
class a_type
{
public:
template <int N>
double segment()
{
return 42;
}
};
template <int M>
double func()
{
a_type<double, 58> a;
return a.segment<1>();
}
int main(int argc, char *argv[])
{
std::cout << func<10>() << std::endl;
return 0;
}
then the code compiles and produces the expected result.
I would be very happy if somebody could enlighten me and show me what I am missing here.
The compiler doesn't know that a.segment is a template (it might depend on the value of M). So you have to tell it:
return a.template segment<1>();
In your second example it knows everything about the type of a, and so there is no problem.
The compiler tells you that it has problems with
a_type<double, M> a;
return a.segment<1>();
because it cannot tell what members a can have, as it is a template (that might be specialized for some values of M).
main.cpp:18:22: error: invalid operands of types '<unresolved overloaded function type>' and 'int' to binary 'operator<'
return a.segment<1>();
^
If segment is a template, it would be treated as segment<1>. If segment is a member variable of a, it should be compiled as a.segment < 1. How is the compiler to know?
You can fix this by using
return a.template segment<1>();

How to declare a self-referential template typedef

Here's a small example which is substantially similar to what I'm trying to do:
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <utility>
#include <vector>
struct foo {
const char * str;
};
typedef std::pair<float, float> fpair;
//typedef std::vector<boost::variant<int, fpair, foo, vlist>> vlist;
// ^ No...
//typedef std::vector<boost::variant<int, fpair, foo, boost::recursive_wrapper<vlist>>> vlist;
// ^ No...
//template <typename T = vlist<T> >
//using vlist = std::vector<boost::variant<int, fpair, foo, boost::recursive_wrapper<vlist>>>;
// ^ No...
template <typename T = vlist<T> >
using vlist = std::vector<boost::variant<int, fpair, foo, boost::recursive_wrapper<T>>>;
// Still no?
int main () {
std::cout << "Hello world\n";
}
The error I get with gcc 4.8 is:
test.cpp:12:33: error: expected nested-name-specifier before ‘vlist’
template <typename T = typename vlist<T>>
^
test.cpp:12:33: error: expected ‘>’ before ‘vlist’
The error with clang 3.6 is:
test.cpp:12:24: error: unknown type name 'vlist'
template <typename T = vlist<T>>
^
test.cpp:12:29: error: expected ',' or '>' in template-parameter-list
template <typename T = vlist<T>>
^
test.cpp:12:32: error: expected unqualified-id
template <typename T = vlist<T>>
^
3 errors generated.
(Edit: actually these errors are from slightly different versions of the above code, but they all give quite similar messages)
I looked at these earlier, slightly different questions, I'm still stumped:
How to declare a self referencing template type
How to properly declare a self-referencing template type?
Boost Fusion adapt declaration for a templated self referential structure
Does anyone know a trick for this, or is there some reason I'm not aware of that the compiler inherently isn't able to do this?
I believe you just want boost::make_recursive_variant:
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <utility>
#include <vector>
struct foo {
const char* str;
};
typedef std::pair<float, float> fpair;
typedef boost::make_recursive_variant<
int,
fpair,
foo,
std::vector<boost::recursive_variant_>
>::type vlist;
int main() {
std::vector<vlist> vec;
vec.push_back(4);
vec.push_back(fpair{1.0f, 2.0f});
vlist v2(vec);
}

How to pass inner typedef which is "int X::*" as template function parameter?

In this code, I want to pass the address of x.y as the template parameter typename Name::Type leValue.
#include <iostream>
using std::cout;
using std::endl;
struct X {
X() : y(123) {}
const int y;
};
template<typename Name, typename Name::Type leValue>
void print() { cout << *leValue << endl; }
struct Foo {
typedef int X::* Type;
};
int main() {
X x;
print<Foo, &x.y>(); // What is the right syntax here?
}
However, with gcc 4.7.2, I get the following errors:
source.cpp: In function 'int main()':
source.cpp:22:5: error: parse error in template argument list
source.cpp:22:22: error: no matching function for call to 'print()'
source.cpp:22:22: note: candidate is:
source.cpp:11:6: note: template void print()
source.cpp:11:6: note: template argument deduction/substitution failed:
source.cpp:22:22: error: template argument 2 is invalid
If I instead change the typedef to typedef int Type;, and the print call to print<Foo, 3>();, then it works. I tried several things by looking at the error messages, but could not get the syntax right. I have also searched here, and found some useful posts dealing with template classes, but none dealing with template functions. I tried using those answers but it did not help.
Could you please help me with this syntax, or explain to me what I should try doing next to fix this?
Is this close to what you're looking for?
#include <iostream>
using std::cout;
using std::endl;
struct X {
X() : y(123) {}
const int y;
};
template<typename Name, typename Type, Type Name::*Member>
void print(Type& obj) { cout << obj.*Member << endl; }
int main() {
X x;
print<X, const int, &X::y>(x);
}
The address of x.y is unknown in compile time. You can take a pointer to the member y as template argument, however, you have to pass the address of the object instance in run-time.
It works when you change it to an int because your allowed to pass const ints as template parameters. Templates will not let you pass values as arguments because they need to be resolved at compile time.

How do I specify the type of a map used with a template?

I first have this simple example that works (my first time using maps). The type of the name-value pairs is a string to a function pointer respectively.
#include <iostream>
#include <map>
using std::cout;
int foo() {
return 243;
}
int main() {
std::map<std::string, int (*)()> list;
list["a"] = foo;
cout << list["a"](); // 243
}
Then I tried using a template to specify the type. Where it says int in the map instantiation is where I'd like to specify the type using a template. So I tried but I don't exactly know where to put <int> where I'm either calling the function or making the name-value pairs. This is what I tried:
#include <iostream>
#include <map>
using std::cout;
int foo() {
return 243;
}
int main() {
template <typename N>
std::map<std::string, N (*)()> list;
list["A"] = <int> foo; // right here where you see <int>
cout << list["A"]();
}
This doesn't work because I don't think I'm putting <int> in the right place. The errors I'm getting are:
/tmp/134535385811595.cpp: In function 'int main()':
/tmp/134535385811595.cpp:11: error: expected primary-expression before 'template'
/tmp/134535385811595.cpp:11: error: expected `;' before 'template'
/tmp/134535385811595.cpp:14: error: 'list' was not declared in this scope
/tmp/134535385811595.cpp:14: error: expected primary-expression before '<' token
/tmp/134535385811595.cpp:14: error: 'N' was not declared in this scope
Can anyone help?
template <typename N>
std::map<std::string, N (*)()> list;
template<typename> syntax is used for definitions of templates. Map class template is already defined elsewhere, you can only provide template parameters when you're instantiating it.
You can do what you want by wrapping your map in a class template:
template<typename ReturnType>
struct Wrapper {
std::map<std::string, ReturnType (*)()> m;
};
and then instantiate and use it like:
int foo() { }
Wrapper<int> w;
w.m["foo"] = foo;

What is causing this template-related compile error?

When I try to compile this:
#include <map>
#include <string>
template <class T>
class ZUniquePool
{
typedef std::map< int, T* > ZObjectMap;
ZObjectMap m_objects;
public:
T * Get( int id )
{
ZObjectMap::const_iterator it = m_objects.find( id );
if( it == m_objects.end() )
{
T * p = new T;
m_objects[ id ] = p;
return p;
}
return m_objects[ id ];
}
};
int main( int argc, char * args )
{
ZUniquePool< std::string > pool;
return 0;
}
I get this:
main.cpp: In member function ‘T* ZUniquePool<T>::Get(int)’:
main.cpp:12: error: expected `;' before ‘it’
main.cpp:13: error: ‘it’ was not declared in this scope
I'm using GCC 4.2.1 on Mac OS X.
It works in VS2008.
I'm wondering whether it might be a variation of this problem:
Why doesn't this C++ template code compile?
But as my error output is only partially similar, and my code works in VS2008, I am not sure.
Can anyone shed some light on what I am doing wrong?
You need typename:
typename ZObjectMap::const_iterator it = m_objects.find( id )
Since the type of ZObjectMap is dependent on the template parameter, the compiler has no clue what ZObjectMap::const_iterator is (it could be a member variable). You need to use typename to inform the compiler to assume it will be some sort of type.
Also to mention, GCC 4.5.0 gives the following output which would help you to solve the problem:
main.cpp: In member function 'T* ZUniquePool<T>::Get(int)':
main.cpp:12:7: error: need 'typename' before 'ZUniquePool<T>::ZObjectMap:: const_iterator' because 'ZUniquePool<T>::ZObjectMap' is a dependent scope
main.cpp:12:34: error: expected ';' before 'it'
main.cpp:13:11: error: 'it' was not declared in this scope
main.cpp: At global scope:
main.cpp:23:5: warning: second argument of 'int main(int, char*)' should be 'char **'