Why does the compiler issue a template recursion error? - c++

I'm currently trying to deduce a std::tuple type from several std::vectors that are passed as parameters. My code works fine using gcc, but the compilation fails with Visual Studio Professional 2019 with the message "fatal error C1202: recursive type or function dependency context too complex".
It has been mentioned for my previous post (C++ "fatal error C1202: recursive type or function dependency context too complex" in visual studio, but gcc compiles) that the problem is caused by template recursion as explained in C++ template compilation error - recursive type or function dependency. However, I don't see where the recursion occurs.
So my questions are:
Why is there an (infinite) recursion?
How can it be resolved?
Here is the code (I'm bound to C++11):
#include <tuple>
#include <vector>
template <typename TT,typename Add>
auto addTupBase(TT t,std::vector<Add> a) ->decltype (std::tuple_cat(t,std::make_tuple(a[0])))
{
return std::tuple_cat(t,std::make_tuple(a[0])) ;
}
template <typename TT,typename Add,typename... Args>
auto addTupBase(TT t,std::vector<Add> a,Args... args)-> decltype(addTupBase(addTupBase(t,a),args...))
{
return addTupBase(addTupBase(t,a),args...);
}
template <typename T,typename... Args>
auto addTup(std::vector<T> in,Args... args) ->decltype(addTupBase(std::make_tuple(in[0]),args...))
{
return addTupBase(std::make_tuple(in[0]),args...);
}
int main()
{
using TupleType = decltype(addTup(std::vector<char>{2},std::vector<int>{5},std::vector<double>{32423}));
TupleType t;
std::get<2>(t) = 342.2;
return 0;
}

MSVC has some conformance issues when running in /permissive mode and "The Microsoft C++ compiler doesn't currently support binding nondependent names when initially parsing a template. This doesn't conform to section 14.6.3 of the C++ 11 ISO specification. This can cause overloads declared after the template (but before the template is instantiated) to be seen.".
If you instead use /permissive- "The compiler [...] implements more of the requirements for two-phase name look-up" and will compile your program as-is.
Also note that you aren't actually using C++11. MSVC 19.24 supports C++14 and up.

Related

is decltype required in trailing return using value of argument type

In trying to understand c++17 compliant code, i am confused by the following code in
which the function uses the value from integral_constant type argument in the
trailing return type. (please feel free to correct my terminolgy etc, trying to learn)
Two simple versions are illustrated below , with and without a decltype on the
argument in the trailing return.
Using Compiler Explorer https://godbolt.org/z/vqmzhu
The first (bool_from1) compiles ok on
MSVC 15.8; /std:c++17, /O2, /permissive-
and clang 8.7.0.0 and gcc 8.2; -std=c++17, -O2, -pedantic
with correct assembler output
The second (bool_from2) errors out on gcc,
It also shows Intellisense errors in VS but compiles without error.
I could not find anything in cppreference or standard draft, etc that would indicate to me that the decltype(atype) would be required for conforming code, however...???
My question would be is the decltype required.
Are my compiler flags correct for c++17 conformance checking.
CODE:
#include <utility>
namespace ns {
volatile bool vb;
template<bool B> struct bool_ : std::bool_constant<B> {};
// using decltype(btype) in trailing return compiles in all 3
template<typename Bool> constexpr auto bool_from1(Bool btype)
-> bool_<decltype(btype)::value> {
return bool_<btype.value>{};
}
void test1() {
static_assert( // simple test
bool_from1(std::true_type{}).value
);
vb = bool_from1(std::true_type{}).value; // check output
}
// without decltype in trailing return compile in VS and clang
// but errors out in gcc; and VS shows Intelisense errors but compiles
template<typename Bool>
constexpr auto bool_from2(Bool btype)
// ^ gcc 8.2 error: deduced class type 'bool_' in function return type
-> bool_<btype.value> {
// ^ gcc: invalid template-id; use of paramter outside function body before '.'
//^ VS Intellisense on btype: <error-constant>; a paramter is not allowed
return bool_<btype.value>{};
}
void test2() {
static_assert(
bool_from2(std::true_type{}).value
//^ gcc: bool_from1 was not declared in this scope
);
vb = bool_from2(std::true_type{}).value; // check output
}
}
This looks like a gcc bug and bug report: "Trailing return types" with "non-type template arguments" which could be "constant expressions" produce a parsing error seems to fit this case:
Consider the following snippet:
template <int>
struct bar {};
template <class I>
auto foo(I i) -> bar<i()> { return {}; }
int main()
{
foo([]{ return 1; }); // (0)
}
This compiles and works as intended on clang++5, but produces a
compile-time error on g++7:
prog.cc:5:25: error: template argument 1 is invalid
auto foo(I i) -> bar<i()> { return {}; }

Function template overload resolution fails in Visual C++ 2017

I am trying to figure out if what I wrote is legal C++14 w.r.t. unambiguous function template overload resolution.
In my opinion, the below program should compile and return 3.
Various versions of Clang and GCC compute just that at compile time (using -std=c++14 -O2), but Visual C++ 2017 (Version 15.5.2; latest update at time of writing) chokes on it with the below error message.
enum class Enum0 { State };
enum class Enum1 { State };
template <Enum0 Param0 = Enum0::State>
int get()
{
return 1;
}
template <Enum1 Param1>
int get()
{
return 2;
}
int main()
{
int sum = 0;
sum += get(); // should call instantiation of first function template
sum += get<Enum1::State>(); // should call instantiation of second function template
return sum;
}
This is the emitted error message by the Visual C++ compiler:
20 : <source>(20): error C2668: 'get': ambiguous call to overloaded function
11 : <source>(11): note: could be 'int get<Enum1::State>(void)'
5 : <source>(5): note: or 'int get<Enum0::State>(void)'
20 : <source>(20): note: while trying to match the argument list '()'
See https://godbolt.org/g/PhH2VY for a live demonstration (and https://godbolt.org/g/BVEv79 for the previous code example before editing the question).
Change the compiler to MVSC to see the compilation failing. GCC and Clang do not indicate any issue. Both nicely emit the following x86 assembly:
mov eax, 3
ret
Are GCC and Clang too lenient, or is this an issue with Visual C++?
That's a good question, isn't it. If I change the second call to get with:
sum += get<Enum1::State, int>(0.0); // should call instantiation of second function template
... then it compiles...
Notice, I add a second template argument. In my day to day work, I use an old dialect of C++ compatible with MFC...so take my reasoning with a grain of salt. But, since you are only providing one argument to the template, and the second template requires two arguments, ISTM that the VC++ compiler is trying to use the first template because it has default arguments and can take only one argument. So it chooses that template but cannot do the conversion from Enum1 to Enum0.

Is C++17 on windows in alignment with C++17 on ubuntu?

I am trying to port some C++17 code I made on ubuntu (gnu++11)
typedef boost::variant<int, float, std::string > Variant;
using Func = std::function<std::vector<unsigned char>(std::vector<Variant>)>;
void addexecutorfunc( Func callback, const auto&...args )
{
std::vector<Variant> vec = {args...};
executor.add(vec, std::move(callback));
}
this code compiles and works fine on ubuntu, but when trying to compile on windows with visual studio 2017(v141) [ISO C++ Latest Draft Standard(/std:c++latest)], then I get following:
error C3533: a parameter cannot have a type that contains 'auto'
I think perhaps it has to do with the Concepts lite not being implemented in current C++17 version or is this wrong?
If I could setup compiler to use auto as parameter and parameter packs, then that would be best, but if this is not possible, then I will have to rewrite my code to follow C++17 windows standard - any suggestions on how to do this without ending up in a template hell
void addexecutorfunc( Func callback, const auto&...args )
auto as a parameter to a (non-lambda) function is a GNU extension. It is not part of standard C++17, and is not supported by either of the other two major C++ compilers, Clang and MSVC. Rather unfortunately, GCC seems to allow it in -std=c++14 mode as well as with -std=gnu++14.
The standard C++ equivalent would be a function template
template <typename... Ts>
void addexecutorfunc(Func callback, const Ts&... args)
which should work as expected.

parameter packs not expanded with ‘...' -- another variadic template bug with gcc?

gcc's treatment of variadic templates is well known to be patchy (see for example this and this), but I wonder whether the following bug is already known (I cannot find it at bugzilla) or whether it is indeed a bug. Essentially, gcc (4.8.1) fails to expand a parameter pack inside a lambda:
#include <vector>
#include <algorithm>
#include <type_traits>
template<typename T, typename F, typename... X>
void bar(std::vector<T> const&c, F const&f, X&&... x)
{
std:for_each(c.begin(),c.end(),[&](const T&t)
{ f(t,std::forward<X>(x)...); });
}
this causes (even without any instantiation)
error: parameter packs not expanded with ‘...’:
{ f(t,std::forward<X>(x)...); });
^
any idea how to avoid that? (note: okay with icpc 14.0.2 and clang 3.4) Or is gcc correct after all and clang & icpc wrong?
edit Note that the problem is the lambda, as also this doesn't compile:
template<typename T, typename F, typename... X>
void bar(std::vector<T> const&c, F const&f, X&&... x)
{
auto func = [&](const T&t){ f(t,std::forward<X>(x)...); };
std:for_each(c.begin(),c.end(),func);
}
with the "error" report in the lambda defiition.
Given that the code compiles cleanly with both clang version 3.5 (trunk 202594) and more importantly with gcc version 4.9.0 20140302 (experimental) (GCC), both with -Wall, I would say it was an issue with the earlier versions of gcc.
I am looking for a gcc bugreport at http://gcc.gnu.org/bugzilla/ to confirm this.

C++11 Variadic Template Function -- where's the error?

The following code gives compilation errors on both MSVC++ 2012 CTP (with C+11 support) and Intel C++ XE 13.0:
template <typename F, typename... Args>
void apply(F f, std::tuple<Args...>& args) {
// doesn't do much yet
}
bool f1(char c) {
return c == 'c';
}
int main(int argc, char* argv[]) {
auto t = std::make_tuple('c');
apply(f1, t);
return 0;
}
VS2012 error is:
error C2243: 'type cast' :
conversion from 'std::tuple<char,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil> *'
to 'std::tuple<std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil> &' exists,
but is inaccessible
Error on Intel C++ XE 13.0 is:
error : no instance of function template "apply" matches the argument list
What am I missing? Are there really errors here, or do I just have two bad compilers?
UPDATE: Same (or similar) results when I use boost::tuple instead of std::tuple on both compilers.
ADDENDUM: Thanks for all the cross-checks in the comments. I've sent bug reports to both of these fine corporations.
That is likely a VC11 bug in the implementation of the Standard Library. Although the CTP supports variadic templates, to the best of my knowledge the Standard Library was not rewritten to use them and adopts some machinery to simulate variadic templates. This is likely at the origin of your problem.