Variadic template pack expansion fails with VS2017 RC but not VS2015 - c++

The test program compiles with VS2015 but not with VS2017 RC. Below is the error I am getting while compiling the test program with VS2017 RC:
/* main.cpp */
#include <type_traits>
template <typename T>
struct A_impl
{
using type = std::false_type;
};
template <typename T>
using A = typename A_impl<T>::type;
template <bool... B>
struct logic_helper;
template <bool... B>
using none_t = std::is_same<logic_helper<B...>, logic_helper<(B && false)...>>;
template <typename... C>
struct Foo
{
// Compile error:
// error C3520: 'C': parameter pack must be expanded in this context
using FooType = none_t<A<C>::value...>;
};
int main()
{
Foo<int, int, int> foo;
return 0;
}
I would like to know why the newest Visual Studio fails to compile the code while the older version has no problem with it. If possible, is there a solution to this compile error for VS2017 RC?

I found a workaround to the problem, but I still can't understand why the compiler complains with my first approach:
template <typename... C>
struct Foo
{
// Workaround
using FooType2 = logic_helper<A<C>::value...>;
using FooType3 = logic_helper<(A<C>::value && false)...>;
using FooType4 = std::is_same<FooType2, FooType3>;
};

Related

Compilation failing in Visual Studio with template template parameter using non-type parameter pack

In Visual Studio I get this compiler error with the below code which I think should compile fine (gcc 11.2 and clang 14.0 compile it). The non-type parameter pack (auto...) means I should be able to pass in a template with any number of non-type template parameters, but the compilation only succeeds when passing in a template that uses a single non-type template parameter.
Is there something I'm missing that will make this work in Visual Studio?
I'm using "/std:c++latest" on Visual Studio 2019, version 16.11.12
error C3201: the template parameter list for class template 'testValues::twoParams' does not match the template parameter list for template parameter 'X'
namespace testValues {
template<template<auto...> class X>
struct templatetemplateparam {};
template<int i>
struct oneParam {};
using oneParam_t = templatetemplateparam<oneParam>;
template<int i, int j>
struct twoParams {};
using twoParams_t = templatetemplateparam<twoParams>;
}
The equivalent code with a specific non-type parameter or a type parameter pack does compile, if that's relevant:
namespace testIntValues {
template<template<int...> class X>
struct templatetemplateparam {};
template<int i>
struct oneParam {};
using oneParam_t = templatetemplateparam<oneParam>;
template<int i, int j>
struct twoParams {};
using twoParams_t = templatetemplateparam<twoParams>;
}
namespace testTypes {
template<template<typename...> class X>
struct templatetemplateparam {};
template<typename>
struct oneParam {};
using oneParam_t = templatetemplateparam<oneParam>;
template<typename, typename>
struct twoParams {};
using twoParams_t = templatetemplateparam<twoParams>;
}
I've reported this to MS at it looks like a bug in Visual Studio to me: https://developercommunity.visualstudio.com/t/Compilation-error-C3021-when-using-value/10015492

Class influences other class behavior in Visual Studio 2015

I have the following code to detect if a type T has a function with a specific return type and parameters parameters (simplified version generated by some more complex macros):
#include <vector>
#include <complex>
#include <type_traits>
namespace has_private
{
template <typename...>
using void_t = void;
template <typename T>
struct identity
{
using type = T;
};
template <typename T>
struct add_const
{
using type = const T;
};
} // namespace has_private
template <typename T, typename = void>
struct has_bytes : std::false_type
{
static_assert(sizeof(T) > 0, "Incomplete type");
};
template <typename T>
struct has_bytes<
T,
has_private::void_t<decltype(std::declval<typename has_private::add_const<T&>::type>().bytes())>>
: std::is_same<decltype(std::declval<typename has_private::add_const<T&>::type>().bytes()), size_t>
{
};
template <typename T, typename = void>
struct has_capacity : std::false_type
{
static_assert(sizeof(T) > 0, "Incomplete type");
};
template <typename T>
struct has_capacity<
T,
has_private::void_t<decltype(std::declval<typename has_private::add_const<T&>::type>().capacity())>>
: std::is_same<decltype(std::declval<typename has_private::add_const<T&>::type>().capacity()), size_t>
{
};
static_assert(has_capacity<std::vector<int>>::value, "should have");
static_assert(has_capacity<std::complex<int>>::value == false, "shouldn't have");
This code compiles fine with VS2019, GCC 7+, clang 7+ but with VS2015 it doesn't compile. If I remove the has_bytes or if I move has_bytes after has_capacity the code compiles with VS2015. By the looks of it this seems to be a compiler bug.
Is this a compiler bug? If yes, do you know any workarounds this bug?
I can't just move the has_bytes after has_capacity because these trait classes are generated using macros from multiple places and their behavior must be reliable.
EDIT:
This is the complete error message:
1>------ Build started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
1>ConsoleApplication1.cpp
1>source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(51): error C2338: should have
1>Done building project "ConsoleApplication1.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
EDIT: I'm using latest version of VS2019 with Visual Studio 2015 (v140) Toolchain. I'm not exactly sure how to check the version in this case

How to use decltype as the LHS of a larger type expression when compiling under VS2010-VS2015

I've got two versions of code both using decltype and declval. One works and one doesn't. They are included below. I've tested this on VS2017 and below and I get the same results. VS2018 will compile it. GCC and Clang both compile it all.
The error that is generated for the failing case under MSVC is
[x86-64 MSVC 19 2017 RTW #1] error C3646: 'type': unknown override
specifier
for the line
typedef typename decltype(boost::declval<Func>()(SegmentVec()))::value_type type;
See God Bolt for a live version of the below code.
#include <vector>
#include "boost/type_traits/declval.hpp"
typedef std::vector<int> SegmentVec;
/////////////////////////////////
// The below fails
template <typename Func> struct Traits {
typedef typename decltype(boost::declval<Func>()(SegmentVec()))::value_type type;
};
template <typename F> auto Hof(F f) -> typename Traits<F>::type {
return f(std::vector<int>{2})[0];
}
/////////////////////////////////
/////////////////////////////////
// The below works
template <typename Func> struct Traits2 {
typedef typename decltype(boost::declval<Func>()(SegmentVec())) type;
};
template <typename F> auto Hof2(F f) -> typename Traits2<F>::type {
return f(std::vector<int>{2});
}
/////////////////////////////////
int main(){
auto lmd = [](std::vector<int> const & a){return a;};
Hof(lmd);
Hof2(lmd);
}
Is it possible to get the code to compile under MSVC 2010 upwards without significantly changing the code. The code in itself above is an extraction from a larger body of code and doesn't necessarily have any meaning apart from demonstrating the compiler error.
To please that buggy MSVC, you can do it in part (demo):
template <typename Func> struct Traits {
typedef decltype(boost::declval<Func>()(SegmentVec())) suptype;
typedef typename suptype::value_type type;
};
using Tnew = Told; is a better syntax though ;)

Undefined type when using std::enable_if and sizeof. (visual studio 2017)

I get what appears to be a Visual Studio bug when I compile time test if a type with a default template parameter has some property. In the minimal example below I use std::is_integer.
When compiling the following program with Visual Studio 2017
#include <type_traits>
#include <utility>
#include <algorithm>
template<typename U,
typename Enabled = typename std::enable_if<std::is_integral<U>::value>::type>
struct wrapper
{
};
template<typename U, typename storage_type>
using is_small = std::is_void<typename std::enable_if <
(sizeof(wrapper<U, char>) <= sizeof(storage_type))
>::type>;
I get the following output
1>bug.cpp(13): error C2027: use of undefined type 'wrapper<U,char>'
1>bug.cpp(13): note: see declaration of 'wrapper<U,char>'
The same program does compile on g++ 6.1.
The program does compile on Visual Studio when the default parameter Enable is removed. In addition, when I perform the same sizeof(...)<=sizeof(...) test in the following template member function the program compiles fine (with is_small removed).
struct c
{
template<typename U, typename storage_type>
typename std::enable_if<(sizeof(wrapper<U, char>) <= sizeof(storage_type))>::value
foo(U u, storage_type t)
{}
};
Somehow the issue is related to the definition of is_small.
Does anyone know what the issue is? Is it a Visual Studio bug? Is there a workaround?
Edit
Reduced version:
template<class, class> struct A { };
template<int> struct B { };
template<class T> constexpr auto x = sizeof(A<T, int>); // works
template<class T> struct C : B<sizeof(A<T, int>)> { }; // works
template<class T> using D = B<sizeof(A<T, int>)>; // doesn't work
A possible workaround could be to use x instead of is_small.
Bug report submitted: https://developercommunity.visualstudio.com/content/problem/204504/issues-with-sizeof-alias-templates-and-virtual-fun.html

SFINAE std::enable_if fails in visual studio 2015

I was trying to port an open sourced project from linux to window, there are some code that compiles perfectly in linux using either g++ or clang++, but I cannot compile it under MSVC 2015, could anyone tell me how to fix it or how to get around it? I appreciate very much for your help!!!
Here is the code (I have simplified it so you can focus on the key stuff)
template <typename T, class IsMatch = void>
class vc_hashkey
{
public:
static constexpr bool holds_value() { return false; }
};
template <typename T>
class vc_hashkey<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
public:
static constexpr bool holds_value() { return true; }
};
template <typename T, class IsMatch = void>
class vc_hashkey_and_value
{
};
template <typename T>
class vc_hashkey_and_value<T, typename std::enable_if<vc_hashkey<T>::holds_value()>::type>
{
};
That's it, I did not even used these code pieces in my main function. When I tried to compile, the msvc 2015 update RC1 compiler gives me compile errors on the partial specialization of the class vc_hashkey_and_value, saying:
C2039 'type': is not a member of 'std::enable_if<'false, void>'
C2146 syntax error: missing '>' before identifier 'type'
C2064 term does not evaluate to a function taking 0 arguments
Is this a MSVC compiler error, thanks for helping me!!!