Reputation: 1894
I'm writing a template class with a method that performs some bitwise operations, so I want to limit the type in the case this method is used within is_integral
. I took the simple example here and modified a bit as follows:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
A();
T foo(T i) {
static_assert(std::is_integral<T>::value, "Integer required.");
return (i & 2);
}
private:
T x;
};
int main() {
A<double> a;
std::cout << a.foo(3) << std::endl;
return 0;
}
However, compiler gives me 2 compile errors at static_assert()
:
static_assert failed "Integer required."
and at return (i & 2);
:
invalid operands to binary expression ('double' and 'double')
My question is, if it will show the error at line return (i & 2);
anyway, using type_traits
to check for type here seems useless? And, is there anyway to throw the error to console output when it runs, instead of making it unable to be compiled?
Upvotes: 0
Views: 583
Reputation: 302748
My question is, if it will show the error at line
return (i & 2);
anyway, usingtype_traits
to check for type here seems useless?
It's true that it's unfortunate that you get subsequent compile errors anyway, but which compile error do you find more readable?
double
and double
)I know what I did wrong about the first one - I have A<double>
but foo()
requires an integer. No idea about the second. Am I misusing your class template or does it have a bug?
And, is there anyway to throw the error to console output when it runs, instead of making it unable to be compiled?
You want it to be a compile error. Catching errors at compile time is a lot better than catching errors at runtime.
Upvotes: 2
Reputation: 69854
Here's another way to achieve the same thing. You may or may not prefer the error messages:
#include <iostream>
#include <type_traits>
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
class A
{
public:
A();
T foo(T i) {
return (i & 2);
}
private:
T x;
};
int main() {
A<double> a;
std::cout << a.foo(3) << std::endl;
return 0;
}
sample errors:
In file included from /opt/gcc-5.3.0/include/c++/5.3.0/bits/move.h:57:0,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/stl_pair.h:59,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/stl_algobase.h:64,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/char_traits.h:39,
from /opt/gcc-5.3.0/include/c++/5.3.0/ios:40,
from /opt/gcc-5.3.0/include/c++/5.3.0/ostream:38,
from /opt/gcc-5.3.0/include/c++/5.3.0/iostream:39,
from /tmp/gcc-explorer-compiler11636-75-1ve7gbt/example.cpp:1:
/opt/gcc-5.3.0/include/c++/5.3.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::integral_constant<bool, false>::value; _Tp = void]':
19 : required from here
/opt/gcc-5.3.0/include/c++/5.3.0/type_traits:2388:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
/tmp/gcc-explorer-compiler11636-75-1ve7gbt/example.cpp: In function 'int main()':
19 : error: template argument 2 is invalid
A<double> a;
^
20 : error: request for member 'foo' in 'a', which is of non-class type 'int'
std::cout << a.foo(3) << std::endl;
^
Compilation failed
Upvotes: 0
Reputation: 62553
Compiler is trying to report as many errors as it can. static_assert
reports an error, but there is another error as well (using double
argument for &
) so it also is reported.
If you want to limit output to one error, you should have two sfinae-enabled overloads and have a second one (for anything but integrals) consist of a single static_assert
.
As for your last question, the whole purpose of doing static_assert
is to trigger errors at compile time, not runtime.
Upvotes: 0