I am making the naive wheel of type traits's is_base_of. And Here's a minimal demo about my implementation(didn't consider robustness, is_class...).
#include <type_traits>
#include <cstdint>
struct A
{
};
struct B : A
{
};
template
<typename T, typename U>
struct IsBaseOf {
constexpr static bool Test(T* t)
{
return true;
}
constexpr static bool Test(...)
{
return false;
}
constexpr static bool value = IsBaseOf<T,U>::Test(static_cast<U*>(nullptr));
};
int main()
{
static_assert(IsBaseOf<A, B>::value, "Pass");
}
This demo can be compiled by gcc/clang but cannot be compiled by MSVC.
http://rextester.com/ATOC6638
http://rextester.com/IWU81465
When i type it on my laptop's Visual Studio 2015(with update patch 3). It cannot be compiled either, the IDE reminds me that "expression must have constant value" before compiling.
So I wonder how's MSVC support for constexpr, or is my code wrong?
This is almost certainly a bug in MSVC. Especially previous versions had numerous issues with constexpr. Here's just a bunch of them for example. Support for many new features is not all that great yet in MSVC. But it's getting better by the minute. You'll want to always use the latest version to try out this sort of stuff. VisualStudio 2017 compiles this code just fineā¦
Your code compiles with Visual Studio 2017 (cl version 19.15.26726).
You could try adding /std:c++14 or /std:c++latest compiler switch.
Related
The following snippet will compile in GCC 8+, but fails to compile in GCC 7.
template <typename... THINGS>
struct A
{
explicit A(THINGS *... things)
{
(..., [thing = things](){}());
}
};
int main()
{
int thing;
const auto thingy = A{&thing};
}
godbolt
The stated failure is that the parameter pack isn't being expanded: parameter packs not expanded with '...'.
Checking the GCC standards compliance page, fold expressions should be supported in GCC 7.
Is there another flag i need besides std=c++17? (i didn't see one)
Is the standard not yet completely implemented? (i didn't see anything indicating that)
Can i make this work, or is this just a GCC 7 bug i'm going to have to work around?
This is a GCC bug, originally reported in version 8.01, fixed in version 8.2. It seems that the bug also occurs when fold-expressions are not used (the C++11-era "expander trick" mentioned by NathanOliver doesn't work either), so you'll have to use a longer workaround that doesn't require expanding a template parameter pack that is inside a lambda capture. For example:
template <typename THING>
void do_it(THING* thing) {
[thing]{}();
}
explicit A(THINGS *... things)
{
(..., do_it(things));
}
This is a GCC bug. Found the tracked issue, fixed in 8.2.
Using Microsoft Visual C++ 2013 (12.0), I am encountering compile-time errors when using a lambda in a constructor in a variadic template. I have managed to boil it down as shown below (see the lines with the error comments). It appears to be a bug in 12.0 that is not present in 14.0. I haven't tried other versions. Is there any documentation on this bug, perhaps in the form of a release note that clarifies the conditions under which this bug occurs and which states that it has been explicitly fixed?
#include <functional>
// a simple method that can take a lambda
void MyFunction(const std::function<void()>& f) {}
// a simple class that can take a lambda
class MyClass
{
public:
MyClass(const std::function<void()>& f) {}
};
// non-templated test
void test1()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass o([] {}); // OK
}
// non-variadic template test
template<typename T>
void test2()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass o([] {}); // OK
}
// variadic template test
template<typename... T>
void test3()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass a([] {}); // error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
// error C2440: 'initializing' : cannot convert from 'test3::<lambda_12595f14a5437138aca1906ad0f32cb0>' to 'int'
MyClass b(([] {})); // putting the lambda in an extra () seems to fix the problem
}
// a function using the templates above must be present
int main()
{
test1();
test2<int>();
test3<int, int, int>();
return 1;
}
Edit/Update: MSVC 2013 compiler seem to have this bug, latest versions fixed that. GCC and clang compilers don't show any error.
I can't say is that bug or not, back days Microsoft was not so eager to latest C++ standards, it was two steps behind GCC and CLang, and it's not a surprise to know that no-one implement a whole standard in one compiler update. Some stuff from std library may be partially implemented, for example Visual Studio usually implements new features under std::experimental namespace (filesystem for VS2013), but something like compiler lexemes can't be added that way.
For common information about standard compatibility I suggest to use compiler support article https://en.cppreference.com/w/cpp/compiler_support/11 (MSVC means _MSC_VER definition) and
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance more for detailed information about Visual Studio. Here https://en.wikipedia.org/wiki/Microsoft_Visual_C++#Internal_version_numbering you can find _MSC_VER version along with related Visual Studio version, source is https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros.
Based on those articles I believe that your problem lays in between "Variadic templates" and "Lambda expression" both are fully supported from Visual Studio 19.0, searching _MSC_VER 1900 in wiki that means Visual Studio 2015 (Update 2, if to be precise according to Microsoft article).
vs2015 can be compiled normally, because vs2015 can fully support the c++11 standard, you can consider upgrading your vs
When using the C++ LLVM-vs2014 configuration in Visual Studio 2015, this static assert fails. The assert does not fail in clang++, gcc, or even Visual C++. The thiscall attribute is stuck on the function type, even though it's no longer applicable. I've filed a bug report, but I'd like to know if there's a way to forcefully remove the attribute in the meantime. Can thiscall be removed?
#include <type_traits>
template<typename T>
struct remove_member_pointer;
template<typename T, typename U>
struct remove_member_pointer<T U::*> {
using type = T;
};
struct foo;
using input = void(foo::*)();
using expect = void();
using result = typename remove_member_pointer<input>::type;
//This static_assert fails because there is a
//compiler-generated attribute left behind, making
//the type of result actually `void () __attribute__((thiscall))`
static_assert(std::is_same<result, expect>{}, "");
int main() { return{}; }
Microsoft Visual Studio Community 2015
Version 14.0.24720.00 Update 1
I did not find a workaround for VS 2015 Update 1, but this issue does appear to be fixed in VS 2015 Update 2.
In Boost ICL, when I call cardinality() or size() functions on an interval set, the return type is size_t, independent of the type of interval. On 32-bit machines this is a 32-bit unsigned integer. If my intervals, however, are of type int64_t, the cardinality can easily overflow the 32-bit integer. Am I missing something obvious here or is this a serious flaw of this library?
EDIT: example added
The following code compiles and runs without error on 64-bit but not on 32-bit machines, where it throws the assertion.
#include <boost/icl/interval_set.hpp>
int main()
{
boost::icl::interval_set<int64_t> is;
is.add(boost::icl::interval<int64_t>::closed(1, 4294967297LL));
assert(boost::icl::cardinality(is) == 4294967297LL);
}
EDIT: I'm using boost::icl version 1.49.0 on Ubuntu 13.10
EDIT:
This is not particularly a 32/64-bit problem, as the following code wouldn't work on 64-bit either
#include <boost/icl/interval_set.hpp>
int main()
{
boost::icl::interval_set<double> is;
is.add(boost::icl::interval<double>::closed(1, 1.5));
assert(boost::icl::cardinality(is) == 0.5);
}
Reproduced with Boost 1_54 on Ubuntu 14.04.1 LTS
This indeed seems to be a bug. The specialization to fix is
template <class Type>
struct get_size_type<Type, false, false, false>
{
typedef std::size_t type;
};
In icl/type_traits/size_type_of.hpp. Somehow the ICL devs appear not to be testing with -m32 these days.
I've had success replacing it by
// BEGIN SEHE WAS HERE
template <class Type>
struct get_size_type<Type, std::enable_if<not boost::is_arithmetic<Type>::value, mpl::false_>::type::value, false, false>
{
typedef std::size_t type;
};
template <class Type>
struct get_size_type<Type, std::enable_if<boost::is_arithmetic<Type>::value, mpl::false_>::type::value, false, false>
{
typedef typename std::common_type<Type, std::size_t>::type type;
};
// END SEHE WAS HERE
The trait is sadly not very SFINAE friendly, hence the hack to use the first bool template argument for SFINAE. Improvements could be:
use boost type traits only
use integral value deduction from Boost Integer as opposed to common_type<...> for integral types
I've tested this to DoTheRightThing(TM) for interval_set<double> as well as interval_set<uint64_t> on g++ -m32 and -m64.
I'd report this on the mailing list.
Code:
#ifdef _MSC_VER
# pragma warning( disable: 4480 ) // enum base as "nonstandard extension"
#endif
enum ShouldBeFine: char { hola };
enum Choice { a, b, c };
template< Choice c > struct Traits;
template<> struct Traits<a> { typedef char Type; };
template<> struct Traits<b> { typedef wchar_t Type; };
template<> struct Traits<c> { typedef long Type; };
template< Choice c >
struct Blah
{
enum X: typename Traits<c>::Type {};
};
int main()
{}
Only after a Herculean effort to file a bug report with Microsoft, did it occur to me that maybe Visual C++ is correct to refuse it, and g++, which compiles the above fine, is maybe wrong?
EDIT Details: the code fails to compile with Visual C++ 10.0 and with the preview of Visual C++ 11.0. Those compilers spit out some rambling error avalanche beginning with an alleged syntax error. The code compiles fine with MinGW g++ 4.4.1. Dani reports that it compiles fine with CLang. Unfortunately Comeau Online does not support this language feature, so it can't be decided in the way we often did for C++98, just give the code to Comeau.
If I am reading the grammar correctly, you are correct in that this should compile. enum-base is : type-specifier-seq, and type-specifier-seq seems to include pretty much any type name you can think of, including typename Traits<c>::Type. And all three specializations result in Type being integral, which is also required of the enum-base. So That looks kosher to me.
This compiles fine in both clang and g++. In addition, template substitution should occur before the class and the enum inside is created, so it should not matter if its template dependent or not.
This has been fixed in the Visual C++ 11 Beta, released on February 29, 2012.
Note also that the warning you disabled--C4480--has also been fixed, so it is no longer incorrectly emitted in native C++ code when enum class is used.