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
}
Related
Does anyone know why the compilation note is generated for this code? The error occurs when compiling in typename T::value_type e. I checked and value_type exists in vector header typedef _Tp value_type; Thanks
#include <vector>
using namespace std;
template <class T>
void f(T& c)
{
typename T::value_type e = c[0];
}
int main(int argc, char *argv[])
{
vector<int> v = {0, 1};
f(v);
return 0;
}
Compilation:
clang++ -std=c++11 -pedantic -Wall test181.cc && ./a.out
test181.cc:7:28: warning: unused variable 'e' [-Wunused-variable]
typename T::value_type e = c[0];
^
test181.cc:13:5: note: in instantiation of function template specialization
'f<std::vector<int, std::allocator<int> > >' requested here
f(v);
^
1 warning generated.
It's letting you know that you've written to a variable that never gets read, which is usually a code smell. As mentioned in the comments, this is only a warning, not an error.
The note was really pertaining to a warning of an unused variable. Use the variable to get rid of the warning.
I have the following (contrived) code:
#include <utility>
namespace N
{
struct A {};
struct B {};
}
namespace operators
{
bool operator|(N::A, N::B) { return true; };
}
namespace details
{
using namespace operators;
template<typename T, typename U>
using UnionResultType = decltype(std::declval<T>() | std::declval<U>());
}
int main()
{
{
using namespace operators;
using UnionAB = decltype(std::declval<N::A>() | std::declval<N::B>());
static_assert(std::is_same<UnionAB, bool>::value);
}
{
using UnionAB = details::UnionResultType<N::A, N::B>;
}
return 0;
}
GCC has a problem compiling the UnionAB declaration in the second block:
operators.cpp: In substitution of ‘template<class T, class U> using UnionResultType = decltype
((declval<T>() | declval<U>())) [with T = N::A; U = N::B]’:
operators.cpp:31:56: required from here
operators.cpp:19:54: error: no match for ‘operator|’ (operand types are ‘N::A’ and ‘N::B’)
using UnionResultType = decltype(std::declval<T>() | std::declval<U>());
Even though there is a using namespace operators within the scope defining the templated UnionResultType, GCC fails to find the operator overload.
I am using GCC 7.2.0 (C++11, 14, and 17 mode all have the same problem).
Is there some issue in the code, or is this a compiler issue? In case this is a compiler issue, is this a known issue?
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);
}
#include <string>
#include <iostream>
#include <tuple>
#include <utility>
template<typename... T> struct test {
using args_type = std::tuple<T...>;
args_type x;
template<std::size_t... I>
void callme(std::index_sequence<I...>) {
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
}
};
int main() {
}
The error message is
clang-3.7 -std=gnu++1y -Wc++14-extensions test.cpp
test.cpp:15:56: error: expected ')'
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
^
test.cpp:15:20: note: to match this '('
int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...};
^
1 error generated.
The same code seems to compile just fine with G++ 4.9.2. I couldn't find any relevant bug report on Clang yet.
Appears to be a Clang bug, though the lookup of such pseudo-destructor-names is probably defected and subject of open CWG issues, specifically 555 and 399.
The significant bit of the expansion pattern is
std::get<I>(x).std::tuple_element<I, args_type>::type::~type()
Here, the bit between . and () is a pseudo-destructor-name; Qualified name lookup then mandates that
If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier,
the type-names are looked up as types in the scope designated by the
nested-name-specifier. Similarly, in a qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
I.e. type is looked up in std::tuple_element<I, args_type>, where it's found to refer to some type. Note that class-name is a grammatical name for identifiers (and simple-template-ids), and need not refer to an actual class. std::get<I>(x).std::tuple_element<I, args_type>::type::~type then refers to the destructor of type.
Workaround with an auxiliary function:
template <typename T>
void destroy(T& p) {p.~T();}
template<typename... T> struct test {
using args_type = std::tuple<T...>;
args_type x;
template<std::size_t... I>
void callme(std::index_sequence<I...>) {
int _[] = {(destroy(std::get<I>(x)), 0)...};
}
};
Interestingly, hstong from IBM mentioned a couple workarounds that work better.
int _[] = {(std::get<I>(x).::std::tuple_element<I, args_type>::type::~type(), true)...};
or
int _[] = {(std::get<I>(x).std::template tuple_element<I, args_type>::type::~type(), true)...};
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