How to specify template deduction guides for template aliases? - c++

I am trying to make this code compile in VS 2019 (16.10.4) with /std:c++17. The following fails:
namespace my
{
template<class _Key, class _Compare = std::less<_Key>, class _Allocator = std::allocator<_Key>>
using Set = std::set<_Key, _Compare, _Allocator>;
}
void test()
{
std::set set1 = { 1, 2, 3 };
static_assert(std::is_same_v<std::set<int>, decltype(set1)>);
my::Set set2 = { 1, 2, 3 }; // Error here.
static_assert(std::is_same_v<my::Set<int>, decltype(set2)>);
}
with error:
error C2955: 'my::Set': use of alias template requires template argument list
message : see declaration of 'my::Set'
The same code compiles fine on godbolt with gcc -std=c++17 without any deduction guides. See sample.
Is there a way to make this compile on VS 2019 (16.10.4) with /std:c++17? My actual code is quite verbose. I created this minimal reproducible sample and it might just come down to solving this small piece. I also tried specifying deduction guides for my::Set but they have similar errors.

my::Set in your code is an alias template, and class template argument deduction for alias templates is a new feature of C++20: https://en.cppreference.com/w/cpp/compiler_support/20
Experimentally one can find that template argument deduction in this example is available in Visual Studio since version 16.11, please also specify /std:c++20 command-line option. Demo: https://gcc.godbolt.org/z/93jdvfPcn
The same code compiles fine on godbolt with gcc -std=c++17 without any deduction guides.
It is a bug in GCC that it allows class template argument deduction for alias templates in C++17 mode: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103852

Related

Why does the compiler issue a template recursion error?

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.

Couldn't deduce template parameter for Eigen::Matrix

When I try to compile the following function (forward) using MSVC 19.latest I get the following error message.
'Eigen::Matrix<float,ann_output_len<LayerNodeConfig...>::value,1,0,_Rows,1> forward(const
ArtificialNeuralNetwork<InputSize,LayerNodeConfig...> &,const Eigen::Matrix<float,Rows,1,0,_Rows,1> &)':
could not deduce template argument for 'const Eigen::Matrix<float,Rows,1,0,_Rows,1> &' from
'Eigen::Matrix<float,2,1,0,2,1>'
forward interface
template<int InputSize, int ... LayerNodeConfig>
auto forward(const ArtificialNeuralNetwork<InputSize, LayerNodeConfig...>& ann,
const RL::Arrayf<InputSize>& input)
-> typename ANN::output_t<LayerNodeConfig...>
In main function
RL::Arrayf<2> X;
auto Y = forward(sampling_policy, X);
Now what I don't understand is why can't the compiler substitute Rows and _Rows with 2.
Any insight is appreciated.
You can try the full code in godbolt.org using this link, https://godbolt.org/z/7Mj5ee and try to compile it yourself if you like.
Note: I tried to compile the same code with latest GCC compiler and it compiled.
Update - Mar 06, 2021:
I made a workaround by changing the interface of function forward to accept Eigen::DenseBase<Derived> instead of RL::Arrayf<InputSize>.
Anyone who is interested can read more about it here, https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

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.

Error with type alias

I would like to use a type alias to create a template with one argument, from a template with two arguments:
// forward declaration
template<int Id, typename MixtureManager> class MixtureBridge;
/**
* Specialization of the MixtureTraits for the Gaussian_sjk_ model
**/
template<>
struct BridgeTraits<STK::Clust::Gaussian_sjk_>
{
// ... some traits
};
template <typename MixtureManager>
using GaussianBridge_sjk_m = MixtureBridge<STK::Clust::Gaussian_sjk_, MixtureManager>;
I get the following error message:
mixt_GaussianBridges.h:65:1: error: expected unqualified-id before 'using'
What is wrong with my syntax ?
Note: I am working with gcc 4.6.3, on Windows
Template aliases are not supported in gcc 4.6 : https://gcc.gnu.org/gcc-4.6/cxx0x_status.html
upgrade your compiler to a more recent version.
Alias-declarations are only supported from gcc 4.7 onwards
https://gcc.gnu.org/gcc-4.7/changes.html