Is it possible to check whether a class has a certain member function overload from within a template member function?
The best similar problem I was able to find is this one: Is it possible to write a template to check for a function's existence? As I understand it, this doesn't apply in to the case of checking for overloads of functions.
Here a simplified example of how this would be applied:
struct A;
struct B;
class C
{
public:
template<typename T>
void doSomething(std::string asdf)
{
T data_structure;
/** some code */
if(OVERLOAD_EXISTS(manipulateStruct, T))
{
manipulateStruct(data_structure);
}
/** some more code */
}
private:
void manipulateStruct(B& b) {/** some different code */};
}
My question would be if some standard way exists to make the following usage of the code work:
int main(int argc, const char** argv)
{
C object;
object.doSomething<A>("hello");
object.doSomething<B>("world");
exit(0);
}
The only methods I could think of would be to simply create an emtpy overload of manipulateStruct for struct A. Otherwise the manipulation method could of course also be put into the structs to be manipulated, which would make SFINAE an option. Let's assume both of these to not be a possiblity here.
Is there any way to get code similar to the above one to work? Does something similar to OVERLOAD_EXISTS exist, to let the compiler know when to add the manipulateStruct part to the generated code? Or is there maybe some way clever way to make SFINAE work for this case?
Testing overload existence (C++11)
Since C++11, you can use a mix of std::declval and decltype to test for the existence of a specific overload:
// If overload exists, gets its return type.
// Else compiler error
decltype(std::declval<C&>().manipulateStruct(std::declval<T&>()))
This can be used in a SFINAE construct:
class C {
public:
// implementation skipped
private:
// Declared inside class C to access its private member.
// Enable is just a fake argument to do SFINAE in specializations.
template<typename T, typename Enable=void>
struct can_manipulate;
}
template<typename T, typename Enable>
struct C::can_manipulate : std::false_type {};
// Implemented outside class C, because a complete definition of C is needed for the declval.
template<typename T>
struct C::can_manipulate<T,std::void_t<decltype(std::declval<C&>().manipulateStruct(std::declval<T&>()))>> : std::true_type {};
Here I am ignoring the return type of the overload using std::void_t (C++17, but C++11 alternatives should be possible). If you want to check the return type, you can pass it to std::is_same or std::is_assignable.
doSomething implementation
C++17
This can be done with constexpr if:
template<typename T>
void doSomething(std::string asdf) {
T data_structure;
if constexpr (can_manipulate<T>::value) {
manipulateStruct(data_structure);
}
}
The if constexpr will make the compiler discards the statement-true if the condition evaluates to false. Without the constexpr, the compilation will require the function call inside the if to be valid in all cases.
Live demo (C++17 full code)
C++11
You can emulate the if constexpr behaviour with SFINAE:
class C {
// previous implementation
private:
template<typename T, typename Enable=void>
struct manipulator;
}
template<typename T, typename Enable>
struct C::manipulator {
static void call(C&, T&) {
//no-op
}
};
// can_manipulate can be inlined and removed from the code
template<typename T>
struct C::manipulator<T, typename std::enable_if<C::can_manipulate<T>::value>::type> {
static void call(C& object, T& local) {
object.manipulateStruct(local);
}
};
Function body:
template<typename T>
T doSomething()
{
T data_structure;
// replace if-constexpr:
manipulator<T>::call(*this, data_structure);
}
Live demo (C++11 full code)
Related
I have a family of classes in a library that can be "installed" in another class, either as a single member or as an array, dependent on the application. The arrays are indexed with an integer or enum type, dependent on the application (void is used when an array is not meaningful). The installable class itself has no control over the indexing; the application using the class defines the index.
However, I imagine that unwanted specialziations could be created by a typo and compile OK.
I want to constrain the indexing types to only the ones intended for the application, by making the client signal back to the library which associations are OK. I couldn't see a pure template metaprogramming approach, so I thought I'd exploit ODR and explicit specialization of class members.
namespace foo {
template <class P, class ROLE>
struct association
{
static_assert(std::is_enum_v<ROLE>||std::is_integral_v<ROLE>);
static const bool allowed();
};
template <class T>
class bar final
{
public:
bar() = default;
~bar() = default;
};
void do_something() {}
template <class I, class ROLE>
void install(I &&i, ROLE r)
{
if (association<std::decay_t<I>, ROLE>::allowed()) do_something();
}
template <class I>
void install(I &&i)
{
if (association<std::decay_t<I>, void>::allowed()) do_something();
}
}
With the following sample use:
// declare the indexing type
enum myindex { min=0, max=3 };
int main() {
foo::bar<int> foobar;
foo::install(foobar, myindex::min);
return 0;
}
There should be a linker error unless we also add
// add a definiton to make the association with myindex OK
template <> const bool foo::association<bar<int>, myindex>::allowed() { return true; }
In the full code, the value of "allowed" doesn't matter, only the existence of a definition does.
It's a pretty cryptic way of saying "this association is OK", but it works. At least, if you fully specialize association. But this is where the "sometimes" comes in: Some of the templates are supposed to work with any indexing type. It's a pain to make the library user write out specializations for these templates. But the following
template <class T, class ROLE> const bool foo::association<foo::bar<T>, ROLE>::allowed () { return true; }
is a compiler error, because it's not a full specialization.
Is there a way to fully define association::allowed() for all combinations of bar specializations with any ROLE, but force the user to define it for other templates?
If not, is there a better approach that accomplishes this goal? (Hopefull, something that can be used with static_assert because what I have now is charitably called 'clunky').
Remember, myindex cannot be rolled into the library. (I'm sticking to C++17 for the time being).
This case seems like a good place for template variables. One of their use is to make them a kind of a map - which in this case would greatly increase readability of the client code and move everything to compile-time. If you just want to break compilation the following should be fine:
#include <iostream>
#include <type_traits>
// make_association is a variable template which works as a compile-time map
// default value is false_type = no relation
template <typename I,typename ROLE>
constexpr std::false_type make_association;
// isAssociated used as a compile-time "function"
template <typename I, typename R>
using isAssociated = decltype(make_association<std::decay_t<I>,std::decay_t<R>>);
template <typename I, typename ROLE>
void install( I &&i, ROLE r)
{
static_assert(isAssociated<I,ROLE>(), "make_association<I, ROLE> not registered");
static_assert(std::is_enum_v<ROLE> || std::is_integral_v<ROLE> );
std::cout<<"Entered install( I &&, ROLE r)"<<std::endl;
}
template <typename I>
void install( I &&i)
{
static_assert(isAssociated<I,void>(), "make_association<I, void> not registered");
std::cout<<"Entered install( I &&)"<<std::endl;
}
enum WrongIndexT { ok = 1};
enum IndexT { min=0, max=3 };
class ObjT final {};
// a class for which any index works
template <class T> class Any final {};
template <class T, class Index>
constexpr std::true_type make_association<Any<T>, Index>;
// here the relations are set using variable template specialization;
template<> constexpr std::true_type make_association<ObjT, IndexT>;
template<> constexpr std::true_type make_association<ObjT, void>;
int main() {
ObjT f1,f2,f3;
install(f1, IndexT::min);
install(f2);
install(Any<int>{}, WrongIndexT::ok); // OK
install(f1, WrongIndexT::ok); // compilation error
return 0;
}
I'm using a "traits" pattern where I have a base case expressed as a class template
template <class>
struct DoCache {
constexpr static bool value = false;
};
and I expect users to specialize for their types:
template <>
struct DoCache<MyType> {
constexpr static bool value = true;
static void write2Cache(MyType const&) { /* implementation */ }
static optional<MyType> readFromCache(string name) { /* implementation */ }
};
The typical use is to retrieve and use this as:
// Define a variable template
template <class T>
constexpr bool do_cache_v = DoCache<T>::value;
// Use the above trait in compile time branching:
if constexpr (do_cache_v<T>)
{
write2Cache(arg);
}
There's two problems I have with this code:
A user is only indirectly enforced to provide a "value" member when specializing, let alone making it the proper value (i.e. true). By indirectly I mean they'll get a bunch of compilation errors that one can only solve if they know the answer beforehand.
There's no way of "requiring" them to create the two needed methods, namely write2Cache and readFromCache, let alone having (const) correct types.
In some code-bases I've seen the considerations above being tackled by defining a generator macro like:
#define CACHABLE(Type, Writer, Reader) ...
Is there a better way to it?
Can concepts be used to restrict the way a specialization looks?
Is there a C++17 compatible way?
an answer to any of the above is appreciated
C++17: Curiously recurring template pattern
It seems like a suitable use case for CRTP:
template<typename T>
struct DoCache {
void write2Cache() {
static_cast<T*>(this)->write2Cache();
}
// ...
};
template<typename T>
void write2Cache(DoCache<T>& t) {
t.write2Cache();
}
struct MyType : DoCache<MyType>
{
void write2Cache() { /* ... */ }
};
int main() {
MyType mt{};
write2Cache(mt);
}
Instead of requiring clients to specialize a library type over their own types, you require them to implementes their own types in-terms-of (static polymorphism) the contract/facade of the library type.
C++20: Concepts
With concepts you can skip polymorphism entirely:
template<typename T>
concept DoCachable = requires(T t) {
t.write2Cache();
};
template<DoCachable T>
void write2Cache(T& t) {
t.write2Cache();
}
struct MyType {
void write2Cache() { /* ... */ }
};
struct MyBadType {};
int main() {
MyType mt{};
write2Cache(mt);
MyBadType mbt{};
write2Cache(mbt); // error: ...
// because 'MyBadType' does not satisfy 'DoCachable'
// because 't.write2Cache()' would be invalid: no member named 'write2Cache' in 'MyBadType'
}
However again placing requirements on the definition site of client type (as opposed to specialization which can be done after the fact).
Trait-based conditional dispatch to write2Cache()?
But how is the trait do_cache_v exposed this way?
C++17 approach
Since the CRTP-based approach offers an "is-a"-relationsship via inheritance, you could simply implement a trait for "is-a DoCache<T>":
#include <type_traits>
template<typename>
struct is_do_cacheable : std::false_type {};
template<typename T>
struct is_do_cacheable<DoCache<T>> : std::true_type {};
template<typename T>
constexpr bool is_do_cacheable_v{is_do_cacheable<T>::value};
// ... elsewhere
if constexpr(is_do_cacheable_v<T>) {
write2Cache(t);
}
C++20 approach
With concepts, the concept itself can be used as a trait:
if constexpr(DoCachable<T>) {
write2Cache(t);
}
You can use a concept to sanity check specializations. Here you only need to provide the correct, by name & type, methods hence the ::value member in DoCache can be deprecated:
template <class T>
concept Cacheable = requires (T const& obj) {
{ DoCache<T>::write2Cache(obj) }
-> std::same_as<void>;
{ DoCache<T>::readFromCache(std::string{}) }
-> std::same_as<std::optional<T>>;
};
Usage is similar to the trait:
if constexpr (Cacheable<MyStruct>)
and enforces proper specialization of DoCache.
Demo
The method shown above implies that a user is allowed to specialize DoCache in an improper way, resulting in a "non cacheable" type. To prevent this from happening you can:
Use defensive programming by placing a static_assert(Cacheable<MyStruct>) after the specialization.
Leverage a constexpr static value member again and enforce an all or nothing policy in specializations, i.e. either a specialization is not provided for the type, or the provided specialization contains all members as specified in the concept. This implies you'll use a trait whose template parameter is the concept.
enum class enabler{};
template<typename T>
class X {
template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()>
void func();
void func(int a);
void func(std::string b);
};
I have this class with these 3 overloads for func. I need the second/third versions to be available for both class/non-class types, and the first version to be available only for class types. when I tried to use enable_if as above, the class instantiation for non-class types gives compile error.
For SFINAE to work, the template argument must be deduced. In your case, T is already known by the time you attempt to instantiate func, so if the enable_if condition is false, instead of SFINAE, you get a hard error.
To fix the error, just add a template parameter whose default value is T, and use this new parameter in the enable_if check. Now deduction occurs and SFINAE can kick in for non-class types.
template<typename U = T,
typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()>
void func();
And you don't really need a dedicated enabler type either, this works too
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
I'm not really sure what you're going for with enabler here, but you can't do what you're trying because the declaration for your member function must be valid since T is not deduced by func. To achieve what you want in adding an extra overload, you can use some moderately contrived inheritance.
struct XBaseImpl {
// whatever you want in both versions
void func(int a) { }
void func(std::string b) { }
};
template <typename, bool> struct XBase;
// is_class is true, contains the extra overload you want
template <typename T>
struct XBase<T, true> : XBaseImpl {
static_assert(std::is_class<T>{}, ""); // just to be safe
using XBaseImpl::func;
void func() { } // class-only
};
// is_class is false
template <typename T>
struct XBase<T, false> : XBaseImpl { };
template<typename T>
class X : public XBase<T, std::is_class<T>{}> { };
You are not enabling or disabling something.
You simply want a compile time error in one specific case.
Because of that you don't require to rely on sfinae, a static_assert is enough.
As a minimal, working example:
#include<string>
template<typename T>
class X {
public:
void func() {
static_assert(std::is_class<T>::value, "!");
// do whatever you want here
}
void func(int a) {}
void func(std::string b) {}
};
int main() {
X<int> x1;
X<std::string> x2;
x2.func(42);
x2.func();
x1.func(42);
// compilation error
// x1.func();
}
Once a SO user said me: this is not sfinae, this is - substitution failure is always an error - and in this case you should use a static_assert instead.
He was right, as shown in the above example a static_assert is easier to write and to understand than sfinae and does its work as well.
I have a templated matrix class that I explicitly instantiate for various POD types and custom class types. Some of the member functions however don't make sense for a few of such custom types. For example:
Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types? So far I have avoided the issue by making LoadFile a friend function and then explicitly controlling its instantiation. But I want to know if I can do this when LoadFile is a member function of Matrix.
The first question is whether you really need to control this. What happens if they call that member function on a matrix that stores My_custom_class? Can you provide support in your class (or the template) so that the member function will work?
If you really want to inhibit the use of those member functions for some particular type, then you can use specialization to block the particular instantiation:
template <typename T>
struct test {
void foo() {}
};
template <>
inline void test<int>::foo() = delete;
Or even just add static_asserts to the common implementation verifying the preconditions for what types is it allowed or disallowed?
template <typename T>
struct test {
void foo() {
static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
"Only allowed for int and double");
// regular code
}
};
with std::enable_if, this is the best I can come up with
template< typename T >
struct Matrix {
template< typename T >
Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()
only type int compile while other don't.
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types?
Your best bet here would be to use a static_assert that would create a compiler error when you attempt to call the method in a version of the class instantiated with a blocked type. Using std::enable_if, and other methods that would selectively "disable" a method itself would require you to create partial or full specializations of the class with and without the methods in question in order to prevent compiler errors. For instance, AFAIK, you cannot do the following:
template <typename T>
struct test
{
static const bool value = false;
};
template<>
struct test<double>
{
static const bool value = true;
};
template<typename T>
struct example
{
void print() { cout << "Printing value from print()" << endl; }
typename enable_if<test<T>::value, T>::type another_print()
{
cout << "Printing value from another_print()" << endl;
return T();
}
};
If you attempted to instantiate an example<int>, etc., you would end up with a compiler error at the point of instantiation of the object type. You couldn't simply call example<int>::print() and be okay, and only run into a problem if you chose to call example<int>::another_print(). Specializations of example<T> could get you around the issue, but that can be a bit of a mess. As originally surmised, a static_assert would probably be the easiest case to handle, along with a nice message to the end-user explaining what went wrong.
Keep in mind that creating compiler errors is the goal, and it's a good one to have. If you blocked a method from being instantiated, and the end-user decided to invoke it, you'd end up with a compiler error either way. The version without the static_assert will leave a lot of head-scratching as the user of your class attempts to parse a probably very verbose compiler error message, where-as the static_assert method is direct and to the point.
If the selected set of types is known at compile time, and you are using c++11 with a compiler that supports type aliases, uniform initialization and constexpr (for example gcc 4.7) you can make your code a bit cleaner like this (from previous example above by yngum):
template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template< typename T >
struct Matrix {
template< typename T >
//std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
Matrix<enable_if_t<std::is_integral<T>{}>>
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();
Beware of compatibility of this code, though, because these features have been only recently supported and some compilers don't do yet. You can see more about c++11 compiler support here.
If you could use the TypeLists from the ( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 ) - Loki you could implement something like:
template<bool>
struct Static_Assert;
template<>
struct Static_Assert<true>{};
class B{};
template<typename T>
class A{
public:
A(){
Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
}
};
Then your HasType would be something like:
template<typename T, typename TList>
struct HasType{
enum { value = 0+HasType< T, typename TList::Tail >::value };
};
template<typename T>
struct HasType< T, NullType >{
enum { value = 0 };
};
template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
enum { value = 1 };
};
In the list you can add the classes which you would like prevent to be passed as the template parameters.
I am experimenting with the new features of C++11. In my setup I would really love to use inheriting constructors, but unfortunately no compiler implements those yet. Therefore I am trying to simulate the same behaviour. I can write something like this:
template <class T>
class Wrapper : public T {
public:
template <typename... As>
Wrapper(As && ... as) : T { std::forward<As>(as)... } { }
// ... nice additions to T ...
};
This works... most of the time. Sometimes the code using the Wrapper class(es) must use SFINAE to detect how such a Wrapper<T> can be constructed. There is however the following issue: as far as overload resolution is concerned, the constructor of Wrapper<T> will accept any arguments -- but then compilation fails (and this is not covered by SFINAE) if the type T cannot be constructed using those.
I was trying to conditionally enable the different instantiations of the constructor template using enable_if
template <typename... As, typename std::enable_if<std::is_constructible<T, As && ...>::value, int>::type = 0>
Wrapper(As && ... as) // ...
which works fine as long as:
the appropriate constructor of T is public
T is not abstract
My question is: how to get rid of the above two constraints?
I tried to overcome the first by checking (using SFINAE and sizeof()) whether the expression new T(std::declval<As &&>()...) is well-formed within Wrapper<T>. But this, of course, does not work, because the only way a derived class can use its base's protected constructor is in the member initialization list.
For the second one, I have no idea whatsoever -- and it is the one I need more, because sometimes it is the Wrapper which implements the abstract functions of T, making it a complete type.
I want a solution which:
is correct according to the standard
works in any of gcc-4.6.*, gcc-4.7.* or clang-3.*
Thanks!
This appears to work fine on my local GCC (4.7, courtesy of rubenvb). GCC on ideone prints several "implemented" compiler internal errors though.
I had to make the "implementation details" of the Experiment class public, because for some reasons (which smells like a bug), my version of GCC complains about them being private, even though only the class itself uses it.
#include <utility>
template<typename T, typename Ignored>
struct Ignore { typedef T type; };
struct EatAll {
template<typename ...T>
EatAll(T&&...) {}
};
template<typename T>
struct Experiment : T {
public:
typedef char yes[1];
typedef char no[2];
static void check1(T const&);
static void check1(EatAll);
// if this SFINAE fails, T accepts it
template<typename ...U>
static auto check(int, U&&...u)
-> typename Ignore<no&,
decltype(Experiment::check1({std::forward<U>(u)...}))>::type;
template<typename ...U>
static yes &check(long, U&&...);
public:
void f() {}
template<typename ...U,
typename std::enable_if<
std::is_same<decltype(Experiment::check(0, std::declval<U>()...)),
yes&>::value, int>::type = 0>
Experiment(U &&...u):T{ std::forward<U>(u)... }
{}
};
// TEST
struct AbstractBase {
protected:
AbstractBase(int, float);
virtual void f() = 0;
};
struct Annoyer { Annoyer(int); };
void x(Experiment<AbstractBase>);
void x(Annoyer);
int main() {
x({42});
x({42, 43.f});
}
Update: The code also works on Clang.