Boost Fusion compile error in VS 2013 RC - c++

Hello I got the latest Boost from trunk which builds with VS 2013 RC. Built boost, it worked.
But when compiling my project against Boost, where I make use of Boost Fusion. I'm getting 100's of these error messages--
Error 1086 error C3520: 'T' : parameter pack must be expanded in this context
It refers to this code in make_vector10.hpp
namespace result_of
{
template <typename T0 , typename T1 , typename T2>
struct make_vector<T0 , T1 , T2>
{
typedef vector3<typename detail::as_fusion_element<T0>::type , typename detail::as_fusion_element<T1>::type , typename detail::as_fusion_element<T2>::type> type;
};
}
But there is no template parameter "T" used anywhere here.
This is also not a variadic template so I don't understand why it refers to parameter packs in the error message. "vector3" and "as_fusion_element" are also not variadic.
All variations of make_vector are giving me the same error btw(also make_set).
Anyone know what is going on here? Thanks
Here is a minimal repro
#include <boost/fusion/container.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/support/pair.hpp>
#include <boost/fusion/include/pair.hpp>
namespace fs = boost::fusion;
namespace Key {
struct prep_table{}; struct draw_single{};
};
int main() {
fs::map<std::pair<Key::prep_table, float>, std::pair<Key::draw_single, int>> Blah;
return 0;
}

It was a compiler bug as reported by Felix Petroconi in the comments.
Work around: get latest boost, but roll back fusion to an earlier version

Related

Undefined reference error from GCC using a template with a std::vector and an Eigen Matrix?

I am experiencing an undefined reference error, when compiling the following code using GCC
4.7.2 20130108 under x86_64-suse-linux via the command:
g++ main.cpp func.cpp -I/path/to/eigenlibrary/eigen_3.2.1
The error message reads:
main.cpp:(.text+0x1d): undefined reference to `void f<2>(std::vector<Eigen::Matrix<double, 2, 2,
((Eigen::._84)0)|((((2)==(1))&&((2)!=(1)))?
((Eigen::._84)1) : ((((2)==(1))&&((2)!=(1)))?((Eigen::._84)0) : ((Eigen::._84)0))), 2, 2>,
std::allocator<Eigen::Matrix<double, 2, 2, ((Eigen::._84)0)|((((2)==(1))&&((2)!=(1)))?
((Eigen::._84)1) : ((((2)==(1))&&((2)!=(1)))?((Eigen::._84)0) : ((Eigen::._84)0))), 2, 2> > >&)'
Please note that this has nothing to do with the fact that the template implementation is separated from the header file, because there is no (generic) implementation of the template function, but only a template specialization. The implementation of the template specialization can not be put into the header file, because this yields multiple definition errors.
Another strange thing here is that if I change the order of the first two header inclusions in main.cpp (Eigen/Dense and vector) the error does not occur. I have no understanding for this and any help that goes beyond 'simply change the order of the header inclusions then' would be highly appreciated.
main.cpp:
#include <vector>
#include <Eigen/Dense>
//error does not occur once I change order of header inclusion like so:
//#include <Eigen/Dense>
//#include <vector>
#include "func.h"
int main() {
std::vector<Eigen::Matrix<double, 2, 2> > m;
f<2>(m);
}
func.h
#ifndef FUNC_H
#define FUNC_H
#include <Eigen/Dense>
#include <vector>
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N> >& m);
template <> void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m);
#endif
func.cpp
#include "func.h"
#include <vector>
template <>
void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m) {}
In func.h, your template specialization declaration should read:
template <> void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m);
So, with the N=2 filled in throughout, as you did with the definition in func.cpp.
Note that you should be able to define your template specialization in func.h if you add inline to the definition.
I can reproduce the failure using GCC 4.6.4, 4.7.4, 4.8.2, 4.9.0, but NOT Clang 3.4.2, all on Arch Linux:
$ echo $'func.h\n---'; cat func.h; echo $'---\nfunc.c++\n---'; cat func.c++; echo $'---\nmain.c++\n---'; cat main.c++; g++-4.6 -I/usr/include/eigen3 main.c++ func.c++; ./a.out
func.h
---
#ifndef FUNC_H
#define FUNC_H
#include <Eigen/Dense>
#include <vector>
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N> >& m);
template <> void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m);
#endif
---
func.c++
---
#include "func.h"
#include <vector>
template <>
void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m) {}
---
main.c++
---
#include <vector>
#include <Eigen/Dense>
//error does not occur once I change order of header inclusion like so:
//#include <Eigen/Dense>
//#include <vector>
#include "func.h"
int main() {
std::vector<Eigen::Matrix<double, 2, 2> > m;
f<2>(m);
}
I strongly suggest contacting the Eigen developers about this.
I know that this is an old question, but we've run into the same problem in a different context, and I thought I would share our solution.
A solution to the unresolved link error, at least for GCC 4.8.2-19ubuntu1, is to replace the following in func.h
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N> >& m);
with
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N, 0> >& m);
Note that the forth template argument is explicitly given as 0, which is the result of the expression shown in the template function declaration in the linker error,
((Eigen::._84)0)|((((2)==(1))&&((2)!=(1)))?
((Eigen::._84)1) : ((((2)==(1))&&((2)!=(1)))?((Eigen::._84)0)
The expression comes from the default value for the forth template parameter, which is given in the Eigen ForwardDeclarations.h file as
AutoAlign |
( (_Rows==1 && _Cols!=1) ? RowMajor
: (_Cols==1 && _Rows!=1) ? ColMajor
: EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION )
There is another way to fix the problem in the Eigen code, which I'll mention in a minute.
The cause of the problem seems to be that the GCC compiler delays the evaluation of this expression and that the expression involves anonymous enum types whose type names are explicitly given in the expression ((Eigen::._84) in this case). Further, the GCC compiler appears to generate anonymous enum type names using a counter, and therefore the type name depends on how many anonymous enum types have appeared before, which can vary for different compilation units. This is why adding #include <vector> or an anonymous enum definition before including Eigen/Dense triggers the problem. The type name in the compiled f<2> is likely (Eigen::._83), and thus the mismatch.
I'm afraid that I'm not an expert on the internals of compilers or the depths of the C++ standard, and can't say if this a bug in the GCC compiler or simply a matter of a difference of interpretation.
Another solution that involves modifying the Eigen code and seems to work is to provide a name for the enum in Constants.h that defines AutoAlign, RowMajor, and ColMajor, as the issue is in using anonymous enum types. For example:
/** \ingroup enums
* Enum containing possible values for the \p _Options template parameter of
* Matrix, Array and BandMatrix. */
enum MatrixOptionsType {
ColMajor = 0,
RowMajor = 0x1,
AutoAlign = 0,
DontAlign = 0x2
};
I'm not sure if that would be acceptable to the Eigen developers, though.

could not deduce template argument in VS 2010

In VS 2005 this code work fine, but in VS 2010 I have error
"could not deduce template argument for 'T *' from 'std::queue<_Ty> *'"
I can't understand what the problem is? Please, help me...
#include <string>
#include <queue>
using namespace std;
template<typename T, typename R, typename P1>
int bindthis(T* obj, R (T::*func)(P1))
{
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::queue<std::wstring> queue_;
bindthis(&queue_, &std::queue<std::wstring>::push);
return 0;
}
I'm not sure about Visual Studio, but in GCC this function compiles in C++03 mode but not in C++11 mode, so I imagine the problem is the same.
The issue is that in C++11, an overload was added to std::queue::push, so the compiler doesn't know which overload to pick. There are two ways to fix this:
Specify the template arguments explicitly:
bindthis<std::queue<std::wstring>, void, const std::wstring&>(&queue_, &std::queue<std::wstring>::push);
Cast the function pointer to the desired type void (std::queue<std::wstring>::*)(const std::wstring&), so that the correct overload is chosen:
typedef void (std::queue<std::wstring>::*push_func_ptr)(const std::wstring&);
bindthis(&queue_, static_cast<push_func_ptr>(&std::queue<std::wstring>::push));

C++ Boost::MPL fold example - wrong number of arguments

I'd like to process some template arguments by using boost::mpl::fold. At the moment, I'm still stuck to the sample provided by Boost as even that does not work for me. I get the following error:
..\src\main.cpp:18:32: error: template argument 2 is invalid
..\src\main.cpp:18:37: error: wrong number of template arguments (4, should be 3)
The following code is taken from http://www.boost.org/doc/libs/1_48_0/libs/mpl/doc/refmanual/fold.html
#include <string>
#include <iostream>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/type_traits.hpp>
using namespace std;
using namespace boost;
using namespace boost::mpl;
using namespace boost::type_traits;
typedef vector<long,float,short,double,float,long,long double> types;
typedef fold<
types
, int_<0>
, if_< is_float<_2>,next<_1>,_1 >
>::type number_of_floats;
BOOST_MPL_ASSERT_RELATION( number_of_floats::value, ==, 4 );
int main(){
}
I'm running mingw 4.7.0 using the flag "-std=c++11". I found some other examples on the net but have not yet been successful in compiling anything useful. Any suggestions?
You are messing up the namespaces. Making a lot of symbols ambiguous.
Remove the using and the example works fine for me.
...
using namespace boost;
typedef mpl::vector<long,float,short,double,float,long,long double> types;
typedef mpl::fold<
types
, mpl::int_<0>
, mpl::if_< is_float<boost::mpl::_2>,boost::mpl::next<boost::mpl::_1>,boost::mpl::_1 >
>::type number_of_floats;
...

Template aliases don't work

I'm trying to get template aliases to work on clang but it doesn't work although the reference sheet says it does
~~~~>$ cat template_alias.cpp
#include <vector>
using namespace std;
template<typename T>
using DoubleVec = vector<vector<T>>;
int main() { return 0; }
~~~~>$ clang template_alias.cpp -o template_alias
template_alias.cpp:6:19: warning: alias declarations accepted as a C++0x extension [-Wc++0x-extensions]
using DoubleVec = vector<vector<T>>;
^
template_alias.cpp:6:34: error: a space is required between consecutive right angle brackets (use '> >')
using DoubleVec = vector<vector<T>>;
^~
> >
template_alias.cpp:6:1: error: cannot template a using declaration
using DoubleVec = vector<vector<T>>;
^
1 warning and 2 errors generated.
~~~~>$ clang -std=c++0x template_alias.cpp -o template_alias
template_alias.cpp:6:1: error: cannot template a using declaration
using DoubleVec = vector<vector<T>>;
^
1 error generated.
Am I doing it wrong?
Your second command (with -std=c++0x) is correct, as is your test case. You might be using a version of clang prior to its support for template aliases. You can check for this by doing:
#if __has_feature(cxx_alias_templates)
Here is a complete list of feature-test macros that clang uses:
http://clang.llvm.org/docs/LanguageExtensions.html#checking_upcoming_features
Here is one, somewhat unpleasant, way to deal with the transition period between support of template aliases and not:
#include <vector>
using namespace std;
#if __has_feature(cxx_alias_templates)
template<typename T>
using DoubleVec = vector<vector<T>>;
#else
template<typename T>
struct DoubleVec {
typedef vector<vector<T> > type;
};
#endif
int main()
{
#if __has_feature(cxx_alias_templates)
DoubleVec<int> v;
#else
DoubleVec<int>::type v;
#endif
}

How to apply an mpl::transform to an mpl::string?

I'm trying to apply a transformation to an mpl::string, but can't get it to compile. I'm using MS VC++2010 and Boost 1.43.0. The code:
#include <boost/mpl/string.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/arithmetic.hpp>
using namespace boost;
int main() {
// this compiles OK
typedef mpl::vector_c<int, 'abcd', 'efgh'> numbers;
typedef mpl::transform<numbers, mpl::plus<mpl::_1, mpl::int_<1> > >::type result_numbers;
// this doesn't (error C2039: 'value' : is not a member of 'boost::mpl::has_push_back_arg')
typedef mpl::string<'abcd', 'efgh'> chars;
typedef mpl::transform<chars, mpl::plus<mpl::_1, mpl::int_<1> > >::type result_chars;
}
I've posted the full error message at http://paste.ubuntu.com/447759/.
The MPL docs say that mpl::transform needs a Forward Sequence, and mpl::string is a Bidirectional Sequence, which I gather is a type of Forward Sequence, so I thought it'd work.
Am I doing something wrong, or is this outright impossible? If so, why?
Thanks!
Turns out that it works if I use transform_view.