In C# or Java, the following does not compile, because I "forgot" the where part in class declaration, that specifies that T is instance of something that defines the add method.
class C<T> {
T make(T t) {
return t.add(t);
}
}
I'd like to get similar compile-time check in C++, if I specify incomplete requires for a template argument.
template <typename T>
requires true
class C {
public:
T make() {
return T{};
}
};
I'd like to get a compile error for the C++ code above, stating that method c.make relies on T being default-constructible, which is however not captured in the requires constraints on T.
Can I get the compiler to check that my set of requires constraints is sufficient to cover everything the class implementation does?
I am using gcc (GCC) 10.0.0 20191207 (experimental) for this.
What I want is called definition checking, and apparently it is not possible currently
C++2a concepts (formerly known as “Concepts Lite” and/or the Concepts TS) famously do not support “definition checking.” The idea of definition checking is that the programmer might write [...]
https://quuxplusone.github.io/blog/2019/07/22/definition-checking-with-if-constexpr/
8.2 Definition checking
Concepts currently do not prevent a template from using operations that are not specified in the requirements. Consider:
template<Number N>
void algo(vector<N>& v){
for (auto& x : v) x%=2;
}
Our Number concept does not require %=, so whether a call of algo succeeds will depend not just on what is checked by the concept, but on the actual properties of the argument type: does the argument type have %=? If not, we get a late (instantiation time) error.
Some consider this a serious error. I don’t [...]
http://www.w.stroustrup.com/good_concepts.pdf
The current proposal checks interfaces and that's where the main benefits for users are, but not template definitions. That has been explicit from the start.
https://isocpp.org/blog/2016/02/a-bit-of-background-for-concepts-and-cpp17-bjarne-stroustrup
template <class T>
requires std::is_default_constructible_v<T>
class C
{
static_assert(std::is_default_constructible_v<T>,
"T is not default-constructible");
};
struct valid
{
};
class invalid
{
invalid() = delete;
};
int main()
{
C<valid>();
// C<invalid>(); // assertion fails.
}
You can write static_assert anywhere inside the class definition, alongside with requires. That will give you an error message you want.
UPDATE After reading the link you have provided, I suppose you just need multiple checks.
You can write a traits struct:
// SFINAE to check if has "add"
template <class T, class = std::void_t<>>
struct has_method_add
{
constexpr static bool value = false;
};
template <class T>
struct has_method_add<T, std::void_t<decltype(&T::add)>>
{
constexpr static bool value = true;
};
template <class T, class = std::void_t<>>
struct has_operator_remainder
{
constexpr static bool value = false;
};
template <class T>
struct has_operator_remainder<T, std::void_t<decltype(&T::operator%=)>>
{
constexpr static bool value = true;
};
template <class T>
struct error_missing_add
{
constexpr static bool value = has_method_add<T>::value;
static_assert(has_method_add<T>::value, "T::add is not defined");
};
template <class T>
struct error_missing_remainder
{
constexpr static bool value = has_operator_remainder<T>::value;
static_assert(has_operator_remainder<T>::value, "T::operator%= is not defined");
};
template <class T>
class C
{
static_assert(std::conjunction_v<error_missing_add<T>, error_missing_remainder<T>>);
// impl...
};
struct valid
{
void add();
int operator%=(int) const;
};
struct missing_add
{
int operator%=(int) const;
};
struct missing_remainder
{
void add();
};
int main()
{
C<valid>{};
C<missing_add>{}; // error: T::add is not defined
C<missing_remainder>{}; // error: T::operator%= is not defined
return 0;
}
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.
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)
I am writing a class designed to shoot random 3D vectors, but I use several geometric libraries in my projects (one included in the 3D simulation, one included in the analysis framework, one which is not included in a more-than-1-GB framework...). Each of these libraries has its own vector definition, with different names for the same method, such has getX(), GetX(), Get(0)... to get the first Cartesian coordinate. But sometimes a common naming convention has been adopted and some method names are the same across two or more libraries.
Of course I want to use this code for any of these vectors, so I implemented a template class. The problem is the following: how do I adapt my code to all these method names, without specializing my class for each implementation (some share the same method names) ?
I managed to write a class using a method or another, now I would like to generalize to any number of method. Something which says: "If you have method 1, use this implementation, if you have method 2, use this other one,... and if you have none, then compilation error".
Currently the class looks like (reduced to the part shooting a random direction):
// First some templates to test the presence of some methods
namespace detail_rand {
// test if a class contains the "setRThetaPhi" method
template<class T>
static auto test_setRThetaPhi(int) ->
decltype(void(std::declval<T>().setRThetaPhi(0.,0.,0.)),
std::true_type{});
template<class T>
static auto test_setRThetaPhi(float)->std::false_type;
}
// true_type if the class contains the "setRThetaPhi" method
template<class T>
struct has_setRThetaPhi : decltype(detail_rand::test_setRThetaPhi<T>(0)) {};
// The actual class
template<class vector>
class Random
{
// everything is static for easy use, might change later
private:
Random() = delete;
Random(Random&) = delete;
// the distribution, random generator and its seed
static decltype(std::chrono::high_resolution_clock::now().time_since_epoch().count()) theSeed;
static std::default_random_engine theGenerator;
static std::uniform_real_distribution<double> uniform_real_distro;
// Shoot a direction, the actual implementation is at the end of the file
private: // the different implementations
static const vector Dir_impl(std::true_type const &);
static const vector Dir_impl(std::false_type const &);
public: // the wrapper around the implementations
inline static const vector Direction() {
return Dir_impl(has_setRThetaPhi<vector>());
}
};
/// initialisation of members (static but template so in header)
// the seed is not of cryptographic quality but here it's not relevant
template<class vector>
decltype(std::chrono::high_resolution_clock::now().time_since_epoch().count())
Random<vector>::theSeed =
std::chrono::high_resolution_clock::now().time_since_epoch().count();
template<class vector>
std::default_random_engine Random<vector>::theGenerator(theSeed);
template<class vector>
std::uniform_real_distribution<double> Random<vector>::uniform_real_distro(0.,1.);
/// Implementation of method depending on the actual type of vector
// Here I use the "setRThetaPhi" method
template<class vector>
const vector Random<vector>::Dir_impl(std::true_type const &)
{
vector v;
v.setRThetaPhi(1.,
std::acos(1.-2.*uniform_real_distro(theGenerator)),
TwoPi()*uniform_real_distro(theGenerator));
return std::move(v);
}
// Here I use as a default the "SetMagThetaPhi" method
// but I would like to test before if I really have this method,
// and define a default implementation ending in a compilation error
// (through static_assert probably)
template<class vector>
const vector Random<vector>::Dir_impl(std::false_type const &)
{
vector v;
v.SetMagThetaPhi(1.,
std::acos(1.-2.*uniform_real_distro(theGenerator)),
TwoPi()*uniform_real_distro(theGenerator));
return std::move(v);
}
Something which says: "If you have method 1, use this implementation, if you have method 2, use this other one,... and if you have none, then compilation error".
I wrote an article that explains how to implement exactly what you need in C++11, C++14 and C++17: "checking expression validity in-place with C++17".
I will synthesize the C++11 and C++14 solutions below - you can use them to normalize all the interfaces you're dealing with by wrapping them inside a single "common" one. You can then implement your algorithms on the "common" interface.
Assume that you have:
struct Cat { void meow() const; };
struct Dog { void bark() const; };
And you want to create a function template make_noise(const T& x) that calls x.meow() if valid, otherwise x.bark() if valid, otherwise produces a compiler error.
In C++11, you can use enable_if and the detection idiom.
You will need to create a type trait for every member you wish to check the existence of. Example:
template <typename, typename = void>
struct has_meow : std::false_type { };
template <typename T>
struct has_meow<T, void_t<decltype(std::declval<T>().meow())>>
: std::true_type { };
Here's an usage example using enable_if and trailing return types - this technique makes use of expression SFINAE.
template <typename T>
auto make_noise(const T& x)
-> typename std::enable_if<has_meow<T>{}>::type
{
x.meow();
}
template <typename T>
auto make_noise(const T& x)
-> typename std::enable_if<has_bark<T>{}>::type
{
x.bark();
}
In C++14, you can use generic lambdas and an implementation of static_if (here's a talk I gave at CppCon 2016 about a possible one) to perform the check with an imperative-like syntax.
You need a few utilities:
// Type trait that checks if a particular function object can be
// called with a particular set of arguments.
template <typename, typename = void>
struct is_callable : std::false_type { };
template <typename TF, class... Ts>
struct is_callable<TF(Ts...),
void_t<decltype(std::declval<TF>()(std::declval<Ts>()...))>>
: std::true_type { };
// Wrapper around `is_callable`.
template <typename TF>
struct validity_checker
{
template <typename... Ts>
constexpr auto operator()(Ts&&...) const
{
return is_callable<TF(Ts...)>{};
}
};
// Creates `validity_checker` by deducing `TF`.
template <typename TF>
constexpr auto is_valid(TF)
{
return validity_checker<TF>{};
}
After that, you can perform all of your checks inside a single overload of make_noise:
template <typename T>
auto make_noise(const T& x)
{
auto has_meow = is_valid([](auto&& x) -> decltype(x.meow()){ });
auto has_bark = is_valid([](auto&& x) -> decltype(x.bark()){ });
static_if(has_meow(x))
.then([&x](auto)
{
x.meow();
})
.else_if(has_bark(x))
.then([&x](auto)
{
x.bark();
})
.else_([](auto)
{
// Produce a compiler-error.
struct cannot_meow_or_bark;
cannot_meow_or_bark{};
})(dummy{});
}
Some macro black magic and if constexpr allow you to write this in C++17:
template <typename T>
auto make_noise(const T& x)
{
if constexpr(IS_VALID(T)(_0.meow()))
{
x.meow();
}
else if constexpr(IS_VALID(T)(_0.bark()))
{
x.bark();
}
else
{
struct cannot_meow_or_bark;
cannot_meow_or_bark{};
}
}
You could solve this by introducing your own names for the operations. Do this by creating a trait class and specialising it for each of the libraries. Something like this:
template <class Vector>
struct VectorTraits;
template <>
struct VectorTraits<Lib1::Vector>
{
static auto getX(const Lib1::Vector &v) { return v.GetX(); }
// ... etc.
};
template <>
struct VectorTraits<Lib2::Vector>
{
static auto getX(const Lib2::Vector &v) { return v.Get(0); }
// ... etc.
};
//Usage:
template <class vector>
auto norm2(const vector &v)
{
using V = VectorTraits<vector>;
return V::getX(v) * V::getX(v) + V::getY(v) + V::getY(v);
}
If you want static assertions for the unsupported operations, you can put them into the unspecialised template:
template <class T>
struct False : std::false_type {};
template <class Vector>
struct VectorTraits
{
static void getX(const Vector &)
{
static_assert(False<Vector>::value, "This type does not support getting x");
}
};
Assume that we have that struct X; and we use C++11 compiler (e.g. gcc 4.7). I'd like to emit some code and attributes if and only if, say, opt = true.
template <bool opt>
struct X {
void foo() {
EMIT_CODE_IF(opt) {
// optional code
}
// ...common code...
}
int optional_variable; // Emitted if and only if opt is true
};
As for the code, I assume that normal if suffices.
But as for the attributes, if one leaves them unused (when opt = false), will and COULD they be automatically omitted by the compiler? I definitely do not want them there when opt = false.
The approach to avoid attributes in a class template is to derive from a base class template which is specialized to be empty if the member shouldn't be there. For example:
template <bool Present, typename T>
struct attribute {
attribute(T const& init): attribute_(init) {}
T attribute_;
};
template <typename T>
struct attribute<false, T> {
};
template <bool opt>
class X: attribute<opt, int> {
...
};
With respect to optional code you may get away with a conditional statement but often the code wouldn't compile. In this case, you'd factor out the code into a suitable function object which be specialized to do nothing when not needed.