static_assert with partial template specialization - c++11

template<typename T, typename U = void>
struct S { /* static_assert(0, "type unsupported"); */ };
template<typename T>
struct S<T, typename std::enable_if<std::is_integral<T>::value, void>::type> {
void foo() {}
};
...
S<int> i;
i.foo();
S<double> d;
// d.foo();
I would be expecting that the "master template" would never be instantiated for the case of int, but if I uncomment the static_assert, the S<int> instantiation will fail. Even a lone typedef S<int> Si; would fail to compile. (GCC 4.9.2 Cygwin)
What I aimed to achieve is not for S<double> to fail at the foo() call, but at the instantiation of the template itself, and that with a meaningful error message. I'm aware I can do something like typename T::nonexistent_type t; in the master template which will prevent the template for compiling, but that'd be inferior to a static_assert message. (Note: putting the static_assert within a function definition in the master template still fails compilation for S<int>)
Why does the static_assert fail even though that template is not instantiated? Is this mandated (or perhaps "unspecified") by the standard? Is there a way to fail with a static_assert the way I wish to?

The expression in the static_assert must be dependent on a template parameter if you wish it to be instantiation-time only. This is guaranteed by Standard- the implementation may (but has no obligation to) check static_assertions in templates that are not dependent on any template parameter.
Your code is a strange roundabout way of doing something like
template<typename T> struct S {
static_assert(std::is_integral<T>::value, "type unsupported");
void foo() {}
};
This clearly communicates to the compiler the dependency between the expression and the template parameter, and is far clearer and easier to read as well. I actually couldn't quite figure out if you wanted compilation to fail for integral types or for non-integral types.

Related

C++ Check if generic object has member function matching signature

first post, so hopefully not violating any etiquette. Feel free to give suggestions for making the question better.
I've seen a few posts similar to this one: Check if a class has a member function of a given signature, but none do quite what I want. Sure it "works with polymorphism" in the sense that it can properly check subclass types for the function that comes from a superclass, but what I'd like to do is check the object itself and not the class. Using some (slightly tweaked) code from that post:
// Somewhere in back-end
#include <type_traits>
template<typename, typename T>
struct HasFunction {
static_assert(integral_constant<T, false>::value,
"Second template parameter needs to be of function type."
);
};
template<typename C, typename Ret, typename... Args>
class HasFunction<C, Ret(Args...)> {
template<typename T>
static constexpr auto check(T*) -> typename is_same<
decltype(declval<T>().myfunc(declval<Args>()...)), Ret>::type;
template<typename>
static constexpr false_type check(...);
typedef decltype(check<C>(0)) type;
public:
static constexpr bool value = type::value;
};
struct W {};
struct X : W { int myfunc(double) { return 42; } };
struct Y : X {};
I'd like to have something like the following:
// somewhere else in back-end. Called by client code and doesn't know
// what it's been passed!
template <class T>
void DoSomething(T& obj) {
if (HasFunction<T, int(double)>::value)
cout << "Found it!" << endl;
// Do something with obj.myfunc
else cout << "Nothin to see here" << endl;
}
int main()
{
Y y;
W* w = &y; // same object
DoSomething(y); // Found it!
DoSomething(*w); // Nothin to see here?
}
The problem is that the same object being viewed polymorphically causes different results (because the deduced type is what is being checked and not the object). So for example, if I was iterating over a collection of W*'s and calling DoSomething I would want it to no-op on W's but it should do something for X's and Y's. Is this achievable? I'm still digging into templates so I'm still not quite sure what's possible but it seems like it isn't. Is there a different way of doing it altogether?
Also, slightly less related to that specific problem: Is there a way to make HasFunction more like an interface so I could arbitrarily check for different functions? i.e. not have ".myfunc" concrete within it? (seems like it's only possible with macros?) e.g.
template<typename T>
struct HasFoo<T> : HasFunction<T, int foo(void)> {};
int main() {
Bar b;
if(HasFoo<b>::value) b.foo();
}
Obviously that's invalid syntax but hopefully it gets the point across.
It's just not possible to perform deep inspection on a base class pointer in order to check for possible member functions on the pointed-to type (for derived types that are not known ahead of time). Even if we get reflection.
The C++ standard provides us no way to perform this kind of inspection, because the kind of run time type information that is guaranteed to be available is very limited, basically relegated to the type_info structure.
Your compiler/platform may provide additional run-time type information that you can hook into, although the exact types and machinery used to provide RTTI are generally undocumented and difficult to examine (This article by Quarkslab attempts to inspect MSVC's RTTI hierarchy)

Why isn't typename interchangeable with decltype() for this usage?

For a given usage
template<typename T1>
class node{
public:
using sp2node = shared_ptr<node<T1>>;
using r_sp2node = shared_ptr<node<T1>>&;
public:
r_sp2Node getN();
private:
sp2node N;
};
(1)
template<typename T1> decltype(node<T1>::r_sp2node) node<T1>::getN(){
return N;
}
(2)
template<typename T1> typename node<T1>::r_sp2node node<T1>::getN(){
return N;
}
(1) generates the compiler error:
error: missing 'typename' prior to dependent type name
'node<T1>::r_sp2node'
whereas (2) compiles
Can someonene explain what is the difference between the above two?
There are two things wrong with the first example.
In decltype(node<T1>::r_sp2node), reading inside out, the compiler first needs to know what node<T1>::r_sp2node. Is it a type, or something else? This is why the typename disambiguator exists, and that is what the error message is all about.
The second problem is that decltype expects some expression, not a type. So even if you used typename, it still wouldn't compile. (As a simple example, decltype(int) won't even compile.)
To answer the question specifically, the difference between the two is that the first is not valid C++ and the second is the way to go.

No member named value in std::is_convertible when using clang

In a very simple situation with a constrained constructor, testing for convertibility of the argument, an error is produced in clang, but not in g++:
#include <type_traits>
template <class T, class U>
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
template <class T>
struct A
{
template <class S, class = std::enable_if_t<Convertible<S,T>> >
A(S const&) {}
};
int main()
{
A<double> s = 1.0;
}
Maybe this issue is related to Is clang's c++11 support reliable?
The error clang gives, reads:
error: no member named 'value' in 'std::is_convertible<double, A<double> >'
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
~~~~~~~~~~~~~~~~~~~~~~~~~~^
I've tried
g++-5.4, g++-6.2 (no error)
clang++-3.5, clang++-3.8, clang++-3.9 (error)
with argument -std=c++1y and for clang either with -stdlib=libstdc++ or -stdlib=libc++.
Which compiler is correct? Is it a bug in clang or gcc? Or is the behavior for some reasons undefined and thus both compilers correct?
First of all, note that it works fine if you use:
A<double> s{1.0};
Instead, the error comes from the fact that you are doing this:
A<double> s = 1.0;
Consider the line below (extracted from the definition of Convertible):
std::is_convertible<U,T>::value
In your case, this is seen as it follows (once substitution has been performed):
std::is_convertible<double, A<double>>::value
The compiler says this clearly in the error message.
This is because a temporary A<double> is constructed from 1.0, then it is assigned to s.
Note that in your class template you have defined a (more or less) catch-all constructor, so a const A<double> & is accepted as well.
Moreover, remember that a temporary binds to a const reference.
That said, the error happens because in the context of the std::enable_if_t we have that A<double> is an incomplete type and from the standard we have this for std::is_convertible:
From and To shall be complete types [...]
See here for the working draft.
Because of that, I would say that it's an undefined behavior.
As a suggestion, you don't need to use std::enable_if_t in this case.
You don't have a set of functions from which to pick the best one up in your example.
A static_assert is just fine and error messages are nicer:
template <class S>
A(S const&) { static_assert(Convertible<S,T>, "!"); }

can std::forward takes std::function<void()> as the class type?

I've always seen std::forward being utilized as below, utilized inside a template function
template<class T>
void foo(T&& arg): bar(std::forward<T>(arg)){}
Suppose I want to do this.
class A
{
private:
std::function<void()> bar;
public:
template<class T>
A(T&& arg):
bar(std::forward<T>(arg))
{}
};
Since bar already has its type defined. I can also directly specify T as std::function<void()> >.
class A
{
private:
std::function<void()> bar;
public:
A(std::function<void()>&& arg):
bar(std::forward<std::function<void()>>(arg))
{}
};
Both would be ok to compile. However, the second realization only support A(const std::function<void()>). While the first realization support A(const std::function<void()>&) and A(std::function<void()>&&) etc.
Forward is a conditional move of its argument. It is almost equivalent to std::move if and only if the type passed to it is a value type or rvalue reference type.
A move is a cast to an rvalue reference.
If you pass a different type to std::forward than its argument type, it will do horrible things. If convertible between, this would often involve creating a temporary within a function then returning a reference to it.
The proper thing to pass to std::forward(x) is X, where the type of x is X&&. Anything else is going to be extremely quirky and advanced use, and will probably cause unexpected behavior...
In your case, the second works fine, but is pointless. As std::forward is a conditional move, and we are passing it a fixed type, we know it is a std::move.
So we should replace std::forward<std::function<void()>>(arg) with std::move(arg), which is both clearer and more conventional. Also, equivalent in this case.
Generally std::forward should only be used in cases where you are using forwarding references.

boost::variant and operator<< overloading

I wanted to test a simple thing like the following:
#include <iostream>
#include <boost/variant.hpp>
template<typename T1,typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1,T2>& dt){
os << dt.first << dt.second;
return os;
}
int main(){
boost::variant<int, std::pair<int,int>, bool> v;
v = std::pair<int,int>(3,3);
std::cout << v << std::endl;
}
This should actually work, because for normal types, like int, double and so on, it compiles.
boost::variant has a printer vistor which it uses internally to output the content to the stream.
Actually this fails to compile, but I do not really know the problem:
The codes fails here: in variant_io.hpp
template <typename OStream>
class printer
: public boost::static_visitor<>
{
private: // representation
OStream& out_;
public: // structors
explicit printer(OStream& out)
: out_( out )
{
}
public: // visitor interface
template <typename T>
void operator()(const T& operand) const
{
out_ << operand; // HEEEEEEERRRRREE!!!!!!!!!!!!
}
private:
printer& operator=(const printer&);
};
With the message:
/usr/local/include/boost/variant/detail/variant_io.hpp|64|error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'
Does someone know what I did wrong, and why?
Thanks a lot!
Most likely it's not finding your overload of operator <<, and then gets confused trying to match some other overload, leading to whatever message you're getting.
What you did wrong: You overloaded the stream operator in the global namespace instead of the namespace the right-hand-side class is defined in, so it's not found by ADL.
Trying to overload the stream operator for a standard class is a doomed exercise in the first place, unfortunately. You can't actually do that. I'm not sure if there is an explicit rule against it. However, if you place the operator in namespace std as you have to in order to make it properly findable by ADL, you violate the rule that you can't add your own stuff to namespace std except in very specific cases, this not being one of them.
The bottom line is that std::pair doesn't have a stream operator, and it's not possible to legally add a generic one that is useful. You can add one for a specific instantiation, if one of the parameters is a class you defined yourself; in this case the operator needs to be placed next to your own class.
Overloaded operator<< must be findable by argument dependent lookup. That means you have to put it in associated namespace of one of the arguments.
The first argument has only one associated namespace, std. The second also has only one associated namespace, std. However it is only permitted to overload symbols in std for user-defined types. Since std::pair<int, int> is not user-defined type, this is not allowed. However it is allowed for a structure or class you define yourself. Obviously in that case it is easier to place the overload to your namespace, not std.
That said if you put that overload in namespace std, it will actually work.
Also note, that boost::tuple does have operator<< (in separate header that you have to include, but it does), so you can use that instead.

Resources