static_assert in templated member function of non-template class - c++

I finally switched to MSVC 2022 in the last couple days and am getting a static_assert from code that had previously been working fine.
I have a type that needs to have a member implemented differently based on whether a template parameter type is trivally constructable and destructable or not, but have not yet actually implemented any of that logic. I've been using static_assert(false, "not yet implemented") as a guard against accidental use of the member.
I've pared it down to the following example:
#include <type_traits>
class TestClass
{
size_t MemberFn() { /* shared stuff between trivial and non-trivial */
return 0;
}
template<typename Type>
size_t MemberFn(std::enable_if_t<!std::is_trivially_constructible_v<Type> || !std::is_trivially_destructible_v<Type>>* = nullptr)
{
static_assert(false, "not implemented yet");
return 0;
}
template<typename Type>
size_t MemberFn(std::enable_if_t<std::is_trivially_constructible_v<Type> && std::is_trivially_destructible_v<Type>>* = nullptr)
{
static_assert(false, "not implemented yet");
return 0;
}
};
When I try building this I get the following (and similar for the second member template):
2>D:\projects\TestLib\TestLib\testlib.h(18,17): error C2338: static_assert failed: 'not implemented yet'
2>D:\projects\TestLib\TestLib\testlib.h(16,9): message : This diagnostic occurred in the compiler generated function 'size_t TestClass::MemberFn(enable_if<!std::is_trivially_constructible_v<Type,>||!std::is_trivially_destructible_v<Type>,void>::type *)'
Note that I do not actually have a call to this function anywhere, and the diagnostic does not tell me what actual type the compiler is trying to use. Basically I wish to go back to this particular function being ignored as it did with MSVC 2019.
I am compiling with /std:c++latest and /permissive- and would prefer to keep those.
What am I missing here?

[dcl.pre]/10
In a static_assert-declaration, the constant-expression is contextually converted to bool and the converted expression shall be a constant expression ([expr.const]). If the value of the expression when so converted is true, the declaration has no effect. Otherwise, the program is ill-formed, and the resulting diagnostic message ([intro.compliance]) should include the text of the string-literal, if one is supplied.
By putting false in your static_assert you've made the program ill-formed and the compiler is correct when rejecting the program.
A possible workaround could be to make the assertion dependent on the template parameter, at least superficially.
template<class>
struct always_false : std::false_type {};
template<class T>
inline constexpr bool always_false_v = always_false<T>::value;
class TestClass {
size_t MemberFn() { /* shared stuff between trivial and non-trivial */
return 0;
}
template <typename Type>
size_t MemberFn(
std::enable_if_t<!std::is_trivially_constructible_v<Type> ||
!std::is_trivially_destructible_v<Type>>* = nullptr) {
static_assert(always_false_v<Type>, "not implemented yet");
return 0;
}
template <typename Type>
size_t MemberFn(
std::enable_if_t<std::is_trivially_constructible_v<Type> &&
std::is_trivially_destructible_v<Type>>* = nullptr) {
static_assert(always_false_v<Type>, "not implemented yet");
return 0;
}
};

Raymond Chen covered this issue in his blog:
How can I create a type-dependent expression that is always false?
auto lambda = [total](auto op, auto value) mutable
{
...
static_assert(false, "Don't know what you are asking me to do.");
...
};
However, this does not compile because the static_assert fails immediately.
The reason is that the controlling expression for the static_assert is not dependent upon the type of the arguments, and therefore it is evaluated when the lambda is compiled, not when the lambda is invoked (and the implicit template instantiated).
In order to defer the static_assert to instantiation, we need to make it type-dependent.
Of what use is a type-dependent expression that is always false?
Last time, we saw how to create a type-dependent expression that is always false, and used it in a potentially-discarded statement so that the assertion failed only if the statement ended up being used.
Another case where you want to defer a static assertion failure to instantiation is if you want to reject a particular specialization.
So, you need to make the static_assert condition be dependent on the template argument. Raymond showed two ways to do that:
Using a custom helper template:
#include <type_traits>
template<typename>
inline constexpr bool always_false_v = false;
class TestClass
{
...
template<typename Type>
size_t MemberFn(std::enable_if_t<!std::is_trivially_constructible_v<Type> || !std::is_trivially_destructible_v<Type>>* = nullptr)
{
static_assert(always_false_v<Type>, "not implemented yet");
return 0;
}
template<typename Type>
size_t MemberFn(std::enable_if_t<std::is_trivially_constructible_v<Type> && std::is_trivially_destructible_v<Type>>* = nullptr)
{
static_assert(always_false_v<Type>, "not implemented yet");
return 0;
}
};
Using sizeof():
#include <type_traits>
class TestClass
{
...
template<typename Type>
size_t MemberFn(std::enable_if_t<!std::is_trivially_constructible_v<Type> || !std::is_trivially_destructible_v<Type>>* = nullptr)
{
static_assert(!sizeof(Type*), "not implemented yet");
return 0;
}
template<typename Type>
size_t MemberFn(std::enable_if_t<std::is_trivially_constructible_v<Type> && std::is_trivially_destructible_v<Type>>* = nullptr)
{
static_assert(!sizeof(Type*), "not implemented yet");
return 0;
}
};

Related

C++20 requires expression does not catch static_assert

I was really excited when I first heard about C++20 constraints and concepts, and so far I've been having a lot of fun testing them out. Recently, I wanted to see if it's possible to use C++20 concepts to test the constraints of classes or functions. For example:
template <int N>
requires (N > 0)
class MyArray { ... };
template <int N>
concept my_array_compiles = requires {
typename MyArray<N>;
};
my_array_compiles<1>; // true
my_array_compiles<0>; // false
At first I didn't have any issues, but I encountered a case where static_assert in a dependent function prevents compilation, even though it appears in a requires expression. Here is an example that illustrates this:
template <bool b>
requires b
struct TestA {
void foo() {}
};
template <bool b>
struct TestB {
static_assert(b);
void foo() {}
};
template <template<bool> class T, bool b>
concept can_foo = requires (T<b> test) {
test.foo();
};
can_foo<TestA, true>; // true
can_foo<TestA, false>; // false
can_foo<TestB, true>; // true
// can_foo<TestB, false>; does not compile
TestA and TestB should work similarly for most use cases (although I found that TestB<false> can be used as a type as long as it isn't instantiated or dereferenced). However, my expectation was that a failed static_assert within a requires expression would cause it to evaluate to false instead. This is especially important for using library code that still uses static_assert. For example, std::tuple_element:
template <class T>
concept has_element_0 = requires {
typename tuple_element_t<0, T>;
};
has_element_0<tuple<int>>; // true
// has_element_0<tuple<>>; does not compile
When I pass in an empty tuple to the above concept, I get the error static_assert failed due to requirement '0UL < sizeof...(_Types)' "tuple_element index out of range". I've tested this on g++ 10.3.0 and clang 12.0.5. I was able to work around this issue by providing a wrapper that uses constraints, but it somewhat defeats the purpose since I am essentially preventing the compiler from seeing the static_assert by enforcing the same condition at a higher level.
template <size_t I, class T>
requires (I >= 0) && (I < tuple_size_v<T>)
using Type = tuple_element_t<I, T>;
template <class T>
concept has_element_0 = requires {
typename Type<0, T>;
};
has_element_0<tuple<int>>; // true
has_element_0<tuple<>>; // false
And it doesn't always work depending on how std::tuple_element is used:
template <size_t I, class T>
requires (I >= 0) && (I < tuple_size_v<T>)
tuple_element_t<I, T> myGet(const T& tup) {
return get<I>(tup);
}
template <class T>
concept has_element_0 = requires (T tup) {
myGet<0>(tup);
};
has_element_0<tuple<int>>; // true
// has_element_0<tuple<>>; does not compile
So ultimately my questions are: is this expected behavior that requires expressions don't take static_assert into account? If so, what was the reason for that design? And finally, is there a better way to accomplish my goal on classes with static_assert without using the above workaround?
Thanks for reading.
Yes, nothing in the content of the stuff you interact with is checked. Just the immediate context of the declaration.
In some cases with decltype the non immediate context of some constructs is checked, but any errors remain hard.
This was done (way back) to reduce the requirements on compilers. Only in what is known as "immediate context" do the compilers need to be able to cleanly back out when they see an error and continue compiling.
Static assert is never suitable for this purpose. Static assert, if hit, ends the compilation.
If you want to avoid the static assert (that is expected to end compilation) then you need to provide an alternative.
Once the concept is designed, create a variant for the not (!) of that concept:
#include <tuple>
#include <variant>
template <std::size_t I, class T>
requires (I >= 0) && (I < std::tuple_size_v<T>)
using Type = std::tuple_element_t<I, T>;
template <class T>
concept has_element_0 = requires {
typename Type<0, T>;
};
bool test1()
{
return has_element_0<std::tuple<int>>; // true
}
bool test2()
{
return has_element_0<std::tuple<>>; // false
}
template <std::size_t I, class T>
requires (I >= 0) && (I < std::tuple_size_v<T>)
std::tuple_element_t<I, T> myGet_impl(const T& tup) {
return get<I>(tup);
}
template <class T>
concept alt_has_element_0 = requires (T tup) {
myGet_impl<0>(tup);
};
template <class T>
auto myGet0();
template <class T>
requires (alt_has_element_0<T>)
auto myGet0(const T& tup)
{
return myGet_impl<0, T>(tup);
}
auto test3()
{
std::tuple<int> X{7};
return myGet0(X); // true
}
template <class T>
requires (!alt_has_element_0<T>)
auto myGet0(const T& tup)
{
return std::monostate{};
}
auto test4()
{
std::tuple<> X;
return myGet0(X); // true
}
see it here;
Notice for test4() to compile, the code above defiles what to do if we do not fulfill the requirements of the concept. I stole std::monostate from variant for this.

c++ function to return "zero" of the appropriate type

I'm trying to write a zero() template function that will always return zero of the appropriate type. This is trivial for base types but I'd like similar behavior for user-defined types (which could provide their own overload). For example
auto i = zero<int>() // i is an in
auto d = zero<double>() // d is a double
auto m = zero<Matrix2d>() // m is a Matrix2d with all elements initialized to zero.
What I have is this:
template <typename T>
T zero() {
return T{}*0; // Clearly not correct for all types, but known incorrect cases should be specialized
}
template <>
int zero<int>() { return 1; } // intentionally wrong for testing
but calling
cout << zero<int>() << endl;
is outputting 0 indicating the specialization is not being called. What am I doing wrong?
*NOTE: The use case is similar to std::accumulate, but imagine the starting value is always zero and we don't want to require the user to pass that in.
UPDATE
As a couple commentors noted, this works in Ideone. Something about my specific implementation is breaking it then. I have:
zero.h:
template <typename T>
constexpr T zero() {
return T{}*0;
}
zero.cpp:
#include "zero.h"
template <>
constexpr int zero<int>() { return 1; }
main.cpp:
#include <iostream>
#include "zero.h"
using namespace std;
int main(int argc, char **argv) {
cout << "int: " << zero<int>() << endl;
}
Never use template function specialization. Well almost never.
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag{};
This lets us pass types around as values.
namespace utility{
template<class T>
T zero(){ return zero(tag<T>);}
template<class T>
T zero( tag_t<T> ) { return T{}*0; }
}
Now to add support for specific types the default implementation does not work for, simply override zero(tag_t<X>) in either the namespace of X (or in utility for types in std or built-in types).
namespace math{
struct matrix2d; // define it
inline matrix2d zero( tag_t<matrix2d> ){ return matrix2d::zero; }
}
ADL will find the correct zero if you utility::zero<X>().
Specialization of template functions works like neither overloading nor specialization of template types. It is fragile and its rules are unique to it; it is very rarely the best solution to any problem. Avoid it.
As template function specialization is fragile, it does not surprise me some detail not show broke your example: the code posted in the OP does not obviously break when naively transcribed. It is still a bad idea: on top of fragiliity, it also forces people writing code in namespace bob to exit it, add a specialization of zero in its namespace, then come back to namespace bob. While doing so the base specializtion of zero must be visible, messing with dependencies. It gets aweful.
Avoid using templates in ".cpp" files.
Some useful references.
Try to move everything into the header file:
zero.h:
template <typename T>
T zero() {
return T{}*0;
}
template <>
int zero<int>() { return 1; }
And delete the file zero.cpp.
EDIT:
If you're using Visual Studio, this could be useful:
This error will also be generated as a result of compiler conformance work that was done in Visual Studio .NET 2003:. For code will be valid in the Visual Studio .NET 2003 and Visual Studio .NET versions of Visual C++, remove template <>.
"The use case is similar to std::accumulate, but imagine the starting value is always zero and we don't want to require the user to pass that in."
As it happens, I have exactly that in my toolbox:
template <typename FwdIter>
inline auto accumulate(FwdIter begin, FwdIter end)
-> typename std::iterator_traits<FwdIter>::value_type
{
return std::accumulate(begin, end,
typename std::iterator_traits<FwdIter>::value_type());
}
The relevant expression is typename std::iterator_traits<FwdIter>::value_type() which calculates the zero value given just the iterator type. You need the typename because value_type is a dependent type.
Use default constructor of type T or use 0 argument:
template <class T>
T zero()
{
return T() /* or T(0)*/;
}

C++ how to check the signature of a template parameter class at compile time

In the code below, I am trying to check the signature of the class that is passed as the second template argument to WTrajectory. In the current implementation, the constructor of WTrajectory compares the types of the template argument T and the template argument of the type that is passed to it as the second argument.
The current implementation can perform the check. However, I would prefer to perform it at compile time, if it is possible. Moreover, I would also like to check if the template argument TWPoint has a member function returnTimeTypeID, also at compile time (a solution that performs this check at run time can be found here: link).
template<typename T>
struct WPoint
{
const std::type_info& returnTimeTypeID(void) const
{return typeid(T);}
};
template<typename T, typename TWPoint>
struct WTrajectory
{
WTrajectory(const TWPoint& wp)
{
compare_types(wp);
}
void compare_types(const TWPoint& wp)
{
if (typeid(T) != wp.returnTimeTypeID())
throw std::runtime_error("Error");
}
};
Since returnTimeTypeID is non-virtual the compiler will know the dynamic type of TWPoint at compile time. So instead of doing a runtime check just change your template:
template<typename T>
struct WTrajectory
{
typedef T TWPoint;
...
The best way to check whether a template type has a perticular method at compile time is to just call the method. You'll get a compilation error if it doesn't provide the needed functionality.
If WPoint contains more than just the type info, then the following code will work
template<typename T>
struct WPoint
{
// ... stuff not related to type checking
};
template<typename T>
struct WTrajectory
{
WTrajectory(const WPoint<T>& wp)
{
}
};
You could remove WPoint if it does not contain anything else besides the type info.

C++: Use #if std::is_fundamental<T>::value for conditional compilation in MSVC 2010

In my template I need to have different code parts based on whether the typename is a fundamental type or not.
Compiling this code gives a C4067 in MSVC (unexpected tokens following preprocessor directive - expected a newline):
template <typename T>
void MyClass<T>::foo()
{
// ... some code here
#if std::is_fundamental<T>::value
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
#else
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}
#endif
The template is to work with both primitive and my own (derived from ASSortable) data types and the error is thrown from template instantiation code:
template class MyClass<char>;
Trying to modify the precompiler expression to this didn't work either:
#if std::is_fundamental<T>::value == true
and produces the same exact warning.
Any ideas how to make this code warning-free?
Edit Another thing that comes to mind is to convert this into a run-time check and live with the "constant if expression" warning... Is there really no way to do this elegantly in a single function with no specializations and no extra bloat?
Edit #2 So the way I solved this (which was obvious, but somehow escaped me...) was to define a bool ASSortable::operator<(const ASSortable& _o) const {return this->before(_o);}; which does the job and makes the code clean (once again).
No more ifs or #ifdefs or any similar clutter in my code!
Can't believe I even asked that question as it had such an obvious and simple answer :(
The common pattern to solve that issue is moving the function to a base class that is specialized and abusing inheritance to bring it to your scope:
template <typename T, bool is_fundamental>
struct Foo_impl {
void foo() {
}
};
template <typename T>
struct Foo_impl<T,true>
{
void foo() { // is fundamental version
}
};
template <typename T>
class Foo : public Foo_impl<T, std::is_fundamental_type<T>::value> {
// ...
};
Another approach would be to implement those as private functions in your class and dispatch to them internally from foo based on the trait. This is really simple and a cleaner solution, but fails if one of the two versions of the foo_impl will not compile. In that case you can use, as others have suggested a template member function to resolve, but I would still offer the non-templated foo as the public interface, forwarding to a private foo_impl template. The reason is that the template in there is an implementation detail to hack conditional compilation, not part of the interface. You don't want user code calling that member function with different template arguments than the type of your own class. Borrowing from pmr's answer:
template <typename T>
struct Foo
{
template <typename U = T,
typename std::enable_if<
std::is_fundamental<U>::value, int >::type* _ = 0
>
void foo() {
std::cout << "is fundamental" << std::endl;
}
//...
That solution allows user code like:
Foo<int> f;
f.foo<std::string>();
Which will instantiate a function that you don't need nor want, and will execute the logic that you don't want. Even if users don't try to fool your class, the fact that is a template in the interface might be confusing and make users think that it is possible to call it for different types.
Preproccessor is run at an early stage of compilation, before the compiler analyzes the types and knows the meaning of std::is_fundamental<T>::value, hence it cannot work this way.
Instead, use specialization:
template<bool> void f();
template<> void f<true>() {
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
}
template<> void f<false>() {
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}
template <typename T>
void MyClass<T>::foo()
{
// ... some code here
f<std::is_fundamental<T>::value>();
}
EDIT: You're likely to need to make f a member function, however it's not directly possible since MyClass<T> is a non-specialized template. You could make f a global which delegates the call to the correct member of MyClass. However, there is another approach.
Using overloading, this becomes:
void MyClass<T>::f(const true_type&) {
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
}
void MyClass<T>::f(const false_type&) {
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}
template <typename T>
void MyClass<T>::foo()
{
// ... some code here
f(std::is_fundamental<T>::type());
}
You are mixing up states of compilation. The preprocessor is run before the actual compiler and has no knowledge of types or templates. It just performs (very) sophisticated text substitution.
There is nothing such as static if1 in current C++, so you have to resort to a different method to enable conditional compilation. For functions I would prefer enable_if.
#include <type_traits>
#include <iostream>
template <typename T>
struct Foo
{
template <typename U = T,
typename std::enable_if<
std::is_fundamental<U>::value, int >::type = 0
>
void foo() {
std::cout << "is fundamental" << std::endl;
}
template <typename U = T,
typename std::enable_if<
!(std::is_fundamental<U>::value), int >::type = 0
>
void foo() {
std::cout << "is not fundamental" << std::endl;
}
};
struct x {};
int main()
{
Foo<int> f; f.foo();
Foo<x> f2; f2.foo();
return 0;
}
1 References:
Video: Static if presented by Alexandrescu in Going Native.
n3322: Walter E. Brown's proposal for static if
n3329: Sutter, Bright and Alexandrescu's proposal for static if
It's pretty much what it says, you can't use :: in preprocessor directives. Actually, the only thing you can use after #if is a constant-expression that is defined before the compile-time. You can find some info here
std::is_fundamental<T>::value == true cannot be used at pre-processing time. I guess you would have to use some SFINAE trick with std::enable_if:
template <typename T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type
MyClass<T>::foo()
{
// ... some code here
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
}
template <typename T>
typename std::enable_if<!std::is_fundamental<T>::value, void>::type
MyClass<T>::foo()
{
// ... some code here
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}

C++ templated function and forward declarations

I'm working on some code that compiles and links (and even has released commercial products) on Windows using MSVC. It doesn't compile with GCC though, I get the following errors:
.../CBaseValue.h: In member function 'bool CBaseValue::InstanceOf()':
.../CBaseValue.h:90:18: error: invalid use of incomplete type 'struct CValueType'
.../CBaseValue.h:11:7: error: forward declaration of 'struct CValueType'
CBaseValue.h
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<_Type>();
}
}
...
}
CValueType.h
class CValueType : public CBaseValue {
public:
...
template <typename _Type>
bool IsDerivedFrom() {
return IsDerivedFrom(_Type::TYPEDATA);
}
...
}
I understand why this is a problem. The base class (CBaseValue) has a templated function that uses a derived class (in this case CValueType).
It looks like MSVC isn't exactly obeying the C++ spec here and I've just been bitten by it. But the MSVC behavior of using the forward declaration until code calling the templated function is actually compiled is also more desirable right now. Does anybody know of a work-around where I can get this code working with GCC without having to rewrite a lot of base code?
From my own research it looks like passing '-fno-implicit-templates' to g++ would help but then I'd need to explicitly define the called template types. There are a lot of them so if I can avoid that I'd prefer it. If the general consensus is that this is my best option... so be it!
And in case anybody is wondering, I'm porting the code over to the Mac which is why we're now using GCC.
This is ill-formed by the Standard, but no diagnostic is required. MSVC is fine not diagnosing this particular case (even when instantiation happens!).
More specifically, the (C++03) Standard rules at 14.6/7
If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required.
So the solution is to just make the type dependent, but arrange it that during instantiation, that type is designated. For example, you can do that by rewriting your template like this
template<typename T, typename> // just ignore second param!
struct make_dependent { typedef T type; };
template <typename Type> // eww, don't use "_Type" in user code
bool InstanceOf() {
typename make_dependent<CValueType, Type>::type* pType = GetType();
// ...
return pType->template IsDerivedFrom<Type>();
// ...
}
It seems that the CBaseValue::InstanceOf() function is useless to anyone not including CValueType.h.
So wait to provide the definition until all needed types are available. (EDIT: This is exactly what is suggested by Charles Bailey's comment that he posted while I was typing -- I guess we think alike.)
CBaseValue.h
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf();
...
}
CValueType.h
class CValueType : public CBaseValue {
public:
...
template <typename T>
bool IsDerivedFrom() {
return IsDerivedFrom(T::TYPEDATA);
}
...
}
template <typename T>
inline bool CBaseValue::InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<T>();
}
}
They seem very tightly coupled though, so maybe having just one header file for both classes, or one public header file that includes the individual headers in the correct order, would be better.