Create different template versions based on member presence - c++

I would like to have a templated function like so:
template <typename T>
void ReadHelper(T vector_array[])
{
// some code
}
Where T is some structure. But there are two different versions of this structure:
struct type1 {
float data;
}
struct type2 {
float data;
bool valid;
}
And I would like for ReadHelper to be able to set that valid flag. What is a good way to write two different templated functions to properly handle the two types of structures? I can certainly write overloaded version for all my types, but it is quite tedious. Is there a
way to set the templates properly to do this? SFINAE perhaps?

SFINAE is definitely a solution! I used Templated check for the existence of a class member function? as a reference.
Here's an example of how you might do it. The has_valid type is the important thing; I used it to make a function dispatch, but you could use it other ways too. In your case, you would just call set_valid(vector_array[i]) or whatever from within your read helper.
// SFINAE check for if T has member valid
// note this doesn't check that the member is a bool
template<class T>
class has_valid
{
template<class X>
static std::true_type check(decltype(X::valid));
// Use this version instead if you want to
// check if X::valid is explicitly a bool
/*
template<class X>
static std::true_type check(std::enable_if_t<
std::is_same_v<decltype(X::valid), bool>,
bool
>);
*/
template<class X>
static std::false_type check(...);
public:
using type = decltype(check<T>(true));
constexpr static auto value = type();
};
// Friendly helpers
template<class T>
using has_valid_t = typename has_valid<T>::type;
template<class T>
constexpr static auto has_valid_v = has_valid<T>::value;
// Function dispatcher; call set_valid, which will use has_valid_t to
// dispatch to one of the overloads of dispatch_set_valid, where you can
// either set or not set the value as appropriate
template<class T>
void dispatch_set_valid(T& t, std::false_type)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template<class T>
void dispatch_set_valid(T& t, std::true_type)
{
t.valid = true;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template<class T>
void set_valid(T& t)
{
dispatch_set_valid(t, has_valid_t<T>());
}
See it in action on compiler explorer: https://godbolt.org/z/sqW17WYc6

Related

How to force member functions of class templates to be instantiated?

I have recently found out that the member functions of class templates aren't instantiated until they're used, which is extremely annoying because it makes certain SFINAE constructs not work. I would like to know how to make sure that a member function of a class template specialization is always instantiated as soon as the class is instantiated -- but only using statements inside the class template definition, so that if the member function could not be instantiated, SFINAE kicks in and the compiler falls back on the general class template.
The code I was planning to use looks like this:
template <typename T, typename U>
class test_type {
// general template; dummy parameter U is to allow specialization.
static const bool value = false;
}
template <typename T>
class test_type<T, T> {
// template specialization
void f(T t) {
// do all sorts of type-specific operations with t
// (e.g., calling member functions)
// if T is not suitable for these operations, I want
// a substitution error to be generated so that the
// general template is used instead
}
static const bool value = true;
}
template <typename T>
using satisfies = test_type<T, T>::value;
The body of the member functions in a class will not be a part of SFINAE. The template gets instantiated depending on the signature, and once the class has been instantiated a faulty member function will lead to a hard error.
What you need to do is build a type_trait that you can place in the template specialization. Here's a toy example that checks for two different member functions.
#include <iostream>
#include <type_traits>
template <typename T>
using check_for_method = std::void_t<decltype(std::declval<T>().run()), decltype(std::declval<T>().go())>;
template <typename T, typename U = void>
class test_type {
public:
static const bool value = false;
};
template <typename T>
class test_type<T, check_for_method<T>> {
public:
void f(T t) {
t.run();
t.go();
}
static const bool value = true;
};
struct Foo {
void run() {
std::cout << "Running\n";
}
};
struct Bar : Foo {
void go() {
std::cout << "Going\n";
}
};
int main() {
test_type<Foo> t1;
test_type<int> t2;
test_type<Bar> t3;
std::cout << t1.value << " " << t2.value << " " << t3.value << std::endl;
t3.f(Bar{});
}

Specialize template for types that contain typedef

I have a template class that needs to be specialized for template parameters that contain specific typedef. So I need two definitions, one for the case it has the typedef and another for the case it does not.
My problem is that I don't see how to negate the SFINAE. I could obviously eliminate the special case for the non-special parameter, but I don't know how to eliminate the default for the special parameter.
So I tried partial specialization like this:
struct NormalType { };
struct SpecialType { typedef int special; };
template <typename T, typename IsSpecial = void>
struct DetectSpecial {
void detected() { std::cout << "Not special...\n"; }
};
template <typename T>
struct DetectSpecial<T, typename T::special> {
void detected() { std::cout << "Special!\n"; }
};
but the specialization does not get used (as SSCCE on ideone).
I have also considered using enable_if, but I don't see how to use it for well-formed vs. non-well-formed expressions rather than true/false.
What is the simplest way to define DetectSpecial differently for types that contain specific typedef (the value of the typedef may be anything; it's presence is important)?
Oh, I am still stuck with some C++03 compilers. I don't think anything change in SFINAE anyway.
The minimal change required is to insert some expression in the specialization that is dependent on T::special and yields void (to match the default argument). For example:
template<class T>
struct void_alias
{
typedef void type;
};
template <typename T>
struct DetectSpecial<T, typename void_alias<typename T::special>::type> {
void detected() { std::cout << "Special!\n"; }
};
Following may help: (C++11) https://ideone.com/XISlZ6 (C++03) https://ideone.com/egKrcL
#include <cstdint>
template <typename U>
class has_special
{
private:
template<typename T> struct dummy;
template<typename T>
static std::uint8_t check(dummy<typename T::special>*);
template<typename T> static std::uint16_t check(...);
public:
static
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t);
};

How do I change a value based on a template parameter?

How do I do the following in C++:
template <typename T>
void Foo(T t)
{
...
call Bar(true) if T is of some specific type U or V
call Bar(false) otherwise
...
}
void Bar(bool b)
{
...
}
I could add a redundant template parameter but it would be, well..., redundant.
I could also try to make Bar a template function and specialize it for U and V but that is not my code and the problem would probably just propagate.
I could create a function CallBar that does nothing but to call Bar(false) and specialize it to call Bar(true) for U and V. But the example is actually a bit oversimplified here. The boolean is used in multiple places in the FooLogger sometimes in calls to functions (so there are multiple Bars) sometimes even in ?: conditionals.
What is the best thing to do here?
The idiomatic solution would be to use traits:
template <typename T>
struct BarTraits {
static const bool value = false;
};
template <>
struct BarTraits<U> {
static const bool value = true;
};
template <>
struct BarTraits<V> {
static const bool value = true;
};
template <typename T>
void Foo(T t)
{
...
Bar(BarTraits<T>::value);
...
}
A possible solution using std::is_same:
template <typename T>
void Foo(T t)
{
Bar(std::is_same<T, int>::value || std::is_same<T, char>::value);
}

Variadic templates - incomplete type

Having this code:
template<class ...Args>
struct Are_Same
{
enum {value = Are_Same<Args...>::value};
};
template<class A,class... C>
struct Are_Same<A,C...>
{
enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE
};
template<class A,class B>
struct Are_Same<A,B>
{
enum {value = std::is_same<A,B>::value};
};
I'm getting error from gcc 4.6.1:
error: incomplete type 'Are_Same' used in
nested name specifier.
I thought that by doing Are_Same<A,C...>::value I will invoke recursive call which at the end will simply expand to Are_Same<A,B>. Obviously it's not the case. Anyone knows where am I making mistake?
I think that the definitions of the templates are wrong, in both cases you are triggering exact recursion. I would have expected the compiler to die with some stackoverflow inside the compiler but a different error is produced...
An implementation of the are_same variadic template could be:
template <class... Args> // base (optional to declare the template)
struct are_same;
template <class A, class B, class... Args> // recursion
struct are_same<A,B,Args...> {
static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};
template <class A, class B> // stop condition
struct are_same<A,B> {
static const bool value = is_same<A,B>::value;
};
Note that in the recursion step, one argument is dropped from the list of arguments, so that the new problem to resolve is a reduced version of the original. This type of template metaprogramming is quite related to recursion, and the same rules apply, to be able to use recursion you need to ensure that each recursive step gets you closer to a solution. In this particular case, given a list of N potentially same types, each step reduces the problem to finding whether N-1 types are the same.
You can use alternatively, as stop condition (replacing the former one) a degenerate version of the are_same problem:
template <class A>
struct are_same<A> {
static const bool value = true;
};
Which is degenerate in the sense that it does not really make sense asking whether a single type *are_same*, but for different metaprogramming tasks it could be appropriate.
A different potentially more efficient algorithm (I am not sure whether the compiler will avoid the instantiation of the template in the recursion step above) that does not depend on is_same could be:
template <class... Args>
struct are_same;
template <class A, class... Args>
struct are_same<A,A,Args...> { // recursion
static const bool value = are_same<A,Args...>::value;
};
template <class A, class B, class... Args>
struct are_same<A,B,Args...> { // cut, A and B are not the same
static const bool value = false;
};
template <class A>
struct are_same<A> { // end of recursion
static const bool value = true;
};
In this case, the compiler will prefer the recursion to the cut steps whenever the two types are the same, so we need not check is_same internally. At the same time, if the compiler goes into the cut step, we don't need to process the rest of the type list, as we already know the answer.
I would do it like this :
#include <type_traits>
#include <iostream>
template <class... Args>
struct are_same
{
static const bool value=true;
};
template <class A, class B, class... Args> // recursion
struct are_same<A,B,Args...> {
static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value;
};
int main()
{
std::cout<< std::boolalpha << are_same< int >::value << std::endl;
std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl;
std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl;
}
Probably simplest implementation could be like this:
template <typename... TList>
struct are_same { constexpr static bool value = false; };
template <typename T, typename... TList>
struct are_same<T, T, TList...> {
constexpr static bool value = are_same<T, TList...>::value;
};
template <typename T>
struct are_same<T> { constexpr static bool value = true; };
Alternatively you can replace stop condition with
template <typename T>
struct are_same<T, T> { constexpr static bool value = true; };
But the first one is more general because are_same<type>::value == true. Another question is what should be are_same<>::value equal to. This gives you false but it is not a big deal to add one more template specialisation like this.
template <>
struct are_same<> { constexpr static bool value = true; };

Templated class specialization where template argument is a template

I wondering if something similar to this is possible. Basically, I have a templated class that occasionally takes objects of templated classes. I would like to specialize it (or just a member function)for a specific templated class, but the 'generic' form of that class.
template<typename T, typename S>
class SomeRandomClass
{
//put something here
};
template<typename T>
class MyTemplateClass
{
void DoSomething(T & t) {
//...something
}
};
template<>
void MyTemplateClass< SomeRandomClass<???> >::DoSomething(SomeRandomClass<???> & t)
{
//something specialized happens here
}
Replacing the question marks with appropriate types (double, etc) works, but I would like it to remain generic. I don't know what to put there, as any types wouldn't have been defined. I've looked around, and learned about template template parameters, and tried various combinations to no avail. Thanks for the help!
It's possible to specialize the class like this
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t) { /* something */ }
};
It's not possible to specialize just the member method, because the specialization is on the class as a whole, and you have to define a new class. You can, however, do
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t);
};
template <>
template <typename T,typename S>
void MyTemplateClass<SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S>& t)
{
// something
}
to split up the declaration and definition.
I'm not completely sure why #Ryan Calhoun specialized the way he did but here's a more terse example:
// class we want to specialize with later on
template<typename T, typename S>
struct SomeRandomClass
{
int myInt = 0;
};
// non-specialized class
template<typename T>
struct MyTemplateClass
{
void DoSomething(T & t)
{
std::cout << "Not specialized" << std::endl;
}
};
// specialized class
template<typename T, typename S>
struct MyTemplateClass< SomeRandomClass<T, S> >
{
void DoSomething(SomeRandomClass<T,S> & t)
{
std::cout << "Specialized" << std::endl;
}
};
You can see that you don't need the redundant syntax used in the accepted answer:
template<>
template<typename T, typename S>
Working Demo
Alternative
You can use type_traits and tag-dispatch within your non-specialized class to specialize just the function.
Let's first make a concept for is_random_class:
// concept to test for whether some type is SomeRandomClass<T,S>
template<typename T>
struct is_random_class : std::false_type{};
template<typename T, typename S>
struct is_random_class<SomeRandomClass<T,S>> : std::true_type{};
And then let's declare our MyTemplateClass again, but this time not templated (because we're not specializing) so we'll call it MyNonTemplatedClass:
class MyNonTemplatedClass
{
public:
template<typename T>
void DoSomething(T & t)
{
DoSomethingHelper(t, typename is_random_class<T>::type());
}
// ...
Notice how DoSomething is now templated, and it's actually calling a helper instead of implementing the logic itself?
Let's break down the line:
DoSomethingHelper(t, typename is_random_class<T>::type());
t is as-before; we're passing along the argument of type T&
typename is_random_class<T>::type()
is_random_class<T> is our concept, and since it derives from std::true_type or std::false_type it will have a ::type defined within the class (Google for "type traits")
::type() 'instantiates' the type specified by is_random_class<T>::type. I say it in quotation marks because we're really going to throw that away as we see later
typename is required because the compiler doesn't know that is_random_clas<T>::type actually names a type.
Now we're ready to look at the rest of MyNonTemplatedClass:
private:
//use tag dispatch. If the compiler is smart it won't actually try to instantiate the second param
template<typename T>
void DoSomethingHelper(T&t, std::true_type)
{
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
}
template<typename T>
void DoSomethingHelper(T&t, std::false_type)
{
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
Full Working Demo v2 Here
Notice that our helper functions are named the same, but overloaded on the second parameter's type. We don't give a name to the parameter because we don't need it, and hopefully the compiler will optimize it away while still calling the proper function.
Our concept forces DoSomethingHelper(T&t, std::true_type) only if T is of type SomeRandomClass, and calls the other for any other type.
The benefit of tag dispatch
The main benefit of tag dispatch here is that you don't need to specialize your entire class if you only mean to specialize a single function within that class.
The tag dispatching will happen at compile time, which you wouldn't get if you tried to perform branching on the concept solely within the DoSomething function.
C++17
In C++17, this problem becomes embarrassingly easy using variable templates (C++14) and if constexpr (C++17).
We use our type_trait to create a variable template that will give us a bool value of true if the provided type T is of type SomeRandomClass, and false otherwise:
template<class T>
constexpr bool is_random_class_v = is_random_class<T>::value;
Then, we use it in a if constexpr expression that only compiles the appropriate branch (and discards the other at compile-time, so the check is at compile-time, not run-time):
struct MyNonTemplatedClass
{
template<class T>
void DoSomething(T& t)
{
if constexpr(is_random_class_v<T>)
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
else
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
type-traits were a way to simulate this without needing a class specialization.
Note that is_random_class here is a stand-in for an arbitrary constraint. In general, if you're only checking for a single nontemplated type, prefer a normal overload because it's more efficient on the compiler.
Demo
C++20
In C++20, we can take this a step further and use a constraint instead of if constexpr by using a requires clause on our templated member function. The downside is that we again move back to two functions; one that matches the constraint, and another that doesn't:
struct MyNonTemplatedClass
{
template<class T> requires is_random_class_v<T>
void DoSomething(T& t)
{
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
}
template<class T> requires !is_random_class_v<T>
void DoSomething(T&)
{
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
Demo
Also in C++ 20, we could explicitly encode a concept and use abbreviated template syntax:
template<class T>
concept IsRandomClass = is_random_class_v<T>;
template<class T>
concept IsNotRandomClass = !is_random_class_v<T>;
// ...
template<IsRandomClass T>
void DoSomething(T& t)
{ /*...*/}
template<IsNotRandomClass T>
void DoSomething(T&)
{ /*...*/}
Demo
All you need to do is just template on what you want to keep generic. Taking what you started with:
template<typename T, typename S>
void MyTemplateClass< SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S> & t)
{
//something specialized happens here
}
EDIT:
Alternatively, if you only want to keep part of the SomeRandomClass generic, you could:
template<typename T>
void MyTemplateClass< SomeRandomClass<T,int> >::DoSomething(SomeRandomClass<T,int> & t)
{
//something specialized happens here
}
Edit: this is a correct answer to a different question.
Using the typename T twice confuses the issue a little, because they are compiled separately and are not connected in any way.
You can overload the method to take a templated parameter:
template <typename T>
class MyTemplateClass
{
void DoSomething(T& t) { }
template <typename U,typename V>
void DoSomething(SomeRandomClass<<U,V>& r) { }
};
This maps U and V in the new method to T' and S' in SomeRandomClass. In this setup, either U or V could be the same type as T, but they don't have to be. Depending on your compiler, you ought to be able to do
MyTemplateClass<string> mine;
SomeRandomClass<int,double> random;
// note: nevermind the non-const ref on the string literal here...
mine.DoSomething("hello world");
mine.DoSomething(random);
and the templated call will be selected as the matching overload without having to respecify the types explicitly.
Edit:
To do with with template specialization makes no difference to the overload of DoSomething. If you specialize the class as follows
template <>
class SomeRandomClass <int,double>
{
// something here...
};
then the overload above will eat up this specialized implementation gladly. Just be sure the interfaces of the specialized template and the default template match.
If what you're wanting is to specialize DoSomething to take a specific pair of types for SomeRandomClass then you've already lost generality...that's what specialization is.
If you want to use provide a template struct as a template argument (with intent to use it inside) without specializing it:
Here is an example, that appends a type to a tuple given a template sfinae struct as a template argument:
template<typename Tuple, typename T, template<typename> class /*SFINAEPredicate*/>
struct append_if;
template<typename T, template<typename> class SFINAEPredicate, typename ... Types>
struct append_if<std::tuple<Types...>, T, SFINAEPredicate>
{
using type = typename std::conditional<SFINAEPredicate<T>::value,
std::tuple<Types..., T>, std::tuple<Types...>>::type;
};
// usage
using tuple_with_int = append_if<std::tuple<>, int, std::is_fundamental>;
This can be used since C++11.