I write a template class dependent on a given type and variadic types, like so:
template<typename ConstType,typename...Inputs>
class ConstantTensor;
Then I write another class, which is generally defined in this way (assume wrong_type whatever type you want, but which is different from the following specialization ):
template<typename T>
class X{
public:
using type=wrong_type;
}
And I also have a specialization of this kind:
template<typename ConstType,typename...Inputs>
class X< ConstantTensor< ConstType ,Inputs...>>
{
public:
using type=right_type;
}
My problem is that, if I define the type ConstantTensor<ConstType,double> and then I want to use X<ConstantTensor<ConstType,double>>::type, the general case is called and not the specialization. So I obtain wrong_type instead of right_type. I guess it has to deal with the double type...Could you explain me why and how can I solve this issue? Thank you in advance.
EDIT:
Here a snippet of code, I hope it works:
class Scalar
{};
template<typename ConstType,typename...Inputs>
class ConstantTensor
{
public:
constexpr ConstantTensor(const Inputs&...inputs)
{}
};
template<typename ConstType,typename...Inputs>
constexpr auto Constant(const Inputs&...inputs)
{return ConstantTensor<ConstType,Inputs...>(inputs...);}
template<typename T>
class X{
public:
using type=int;
};
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...>>{
public:
using type=char;
};
int main()
{
constexpr auto delta=Constant<Scalar>(2.0);
using type= X<decltype(delta)>::type; // this is int not char
}
The problem is that
constexpr auto delta=Constant<Scalar>(2.0);
is a constexpr variable; so it's also const.
So decltype(delta) isn't ConstantTensor<Scalar> but is a ConstantTensor<Scalar> const.
You can verify adding const in partial specialization declaration
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...> const>{ // <-- added const
public:
using type=char;
};
Now you get that type is char.
-- EDIT --
The OP asks
Is there a short/elegant way to deal with both cases, const and non const, without duplicating the code?
I don't know if it's elegant, but it seems to me short enough: you can use a sort of self-inheritance adding the following partial specialization.
template <typename T>
class X<T const> : public X<T>
{ };
So X<ConstantTensor<Scalar> const> inherit from X<ConstantTensor<Scalar>>.
Related
I would like to define a class which inherits from a bunch of classes but which does not hide some specific methods from those classes.
Imagine the following code:
template<typename... Bases>
class SomeClass : public Bases...
{
public:
using Bases::DoSomething...;
void DoSomething(){
//this is just another overload
}
};
The problem is now if just one class does not have a member with the name DoSomething I get an error.
What I already tried was emulating an "ignore-if-not-defined-using" with a macro and SFINAE but to handle all cases this becomes very big and ugly!
Do you have any idea to solve this?
It would be really nice if I could define: "Hey using - ignore missing members".
Here I have some sample code: Godbolt
The problem with Jarod42's approach is that you change what overload resolution looks like - once you make everything a template, then everything is an exact match and you can no longer differentiate between multiple viable candidates:
struct A { void DoSomething(int); };
struct B { void DoSomething(double); };
SomeClass<A, B>().DoSomething(42); // error ambiguous
The only way to preserve overload resolution is to use inheritance.
The key there is to finish what ecatmur started. But what does HasDoSomething look like? The approach in the link only works if there is a single, non-overloaded, non-template. But we can do better. We can use the same mechanism to detect if DoSomething exists that is the one that requires the using to begin with: names from different scopes don't overload.
So, we introduce a new base class which has a DoSomething that will never be for real chosen - and we do that by making our own explicit tag type that we're the only ones that will ever construct. For lack of a better name, I'll name it after my dog, who is a Westie:
struct westie_tag { explicit westie_tag() = default; };
inline constexpr westie_tag westie{};
template <typename T> struct Fallback { void DoSomething(westie_tag, ...); };
And make it variadic for good measure, just to make it least. But doesn't really matter. Now, if we introduce a new type, like:
template <typename T> struct Hybrid : Fallback<T>, T { };
Then we can invoke DoSomething() on the hybrid precisely when T does not have a DoSomething overload - of any kind. That's:
template <typename T, typename=void>
struct HasDoSomething : std::true_type { };
template <typename T>
struct HasDoSomething<T, std::void_t<decltype(std::declval<Hybrid<T>>().DoSomething(westie))>>
: std::false_type
{ };
Note that usually in these traits, the primary is false and the specialization is true - that's reversed here. The key difference between this answer and ecatmur's is that the fallback's overload must still be invocable somehow - and use that ability to check it - it's just that it's not going to be actually invocable for any type the user will actually use.
Checking this way allows us to correctly detect that:
struct C {
void DoSomething(int);
void DoSomething(int, int);
};
does indeed satisfy HasDoSomething.
And then we use the same method that ecatmur showed:
template <typename T>
using pick_base = std::conditional_t<
HasDoSomething<T>::value,
T,
Fallback<T>>;
template<typename... Bases>
class SomeClass : public Fallback<Bases>..., public Bases...
{
public:
using pick_base<Bases>::DoSomething...;
void DoSomething();
};
And this works regardless of what all the Bases's DoSomething overloads look like, and correctly performs overload resolution in the first case I mentioned.
Demo
How about conditionally using a fallback?
Create non-callable implementations of each method:
template<class>
struct Fallback {
template<class..., class> void DoSomething();
};
Inherit from Fallback once for each base class:
class SomeClass : private Fallback<Bases>..., public Bases...
Then pull in each method conditionally either from the base class or its respective fallback:
using std::conditional_t<HasDoSomething<Bases>::value, Bases, Fallback<Bases>>::DoSomething...;
Example.
You might add wrapper which handles basic cases by forwarding instead of using:
template <typename T>
struct Wrapper : T
{
template <typename ... Ts, typename Base = T>
auto DoSomething(Ts&&... args) const
-> decltype(Base::DoSomething(std::forward<Ts>(args)...))
{
return Base::DoSomething(std::forward<Ts>(args)...);
}
template <typename ... Ts, typename Base = T>
auto DoSomething(Ts&&... args)
-> decltype(Base::DoSomething(std::forward<Ts>(args)...))
{
return Base::DoSomething(std::forward<Ts>(args)...);
}
// You might fix missing noexcept specification
// You might add missing combination volatile/reference/C-elipsis version.
// And also special template versions with non deducible template parameter...
};
template <typename... Bases>
class SomeClass : public Wrapper<Bases>...
{
public:
using Wrapper<Bases>::DoSomething...; // All wrappers have those methods,
// even if SFINAEd
void DoSomething(){ /*..*/ }
};
Demo
As Barry noted, there are other drawbacks as overload resolution has changed, making some call ambiguous...
Note: I proposed that solution as I didn't know how to create a correct traits to detect DoSomething presence in all cases (overloads are mainly the problem).
Barry solved that, so you have better alternative.
You can implement this without extra base classes so long as you’re willing to use an alias template to name your class. The trick is to separate the template arguments into two packs based on a predicate:
#include<type_traits>
template<class,class> struct cons; // not defined
template<class ...TT> struct pack; // not defined
namespace detail {
template<template<class> class,class,class,class>
struct sift;
template<template<class> class P,class ...TT,class ...FF>
struct sift<P,pack<>,pack<TT...>,pack<FF...>>
{using type=cons<pack<TT...>,pack<FF...>>;};
template<template<class> class P,class I,class ...II,
class ...TT,class ...FF>
struct sift<P,pack<I,II...>,pack<TT...>,pack<FF...>> :
sift<P,pack<II...>,
std::conditional_t<P<I>::value,pack<TT...,I>,pack<TT...>>,
std::conditional_t<P<I>::value,pack<FF...>,pack<FF...,I>>> {};
template<class,class=void> struct has_something : std::false_type {};
template<class T>
struct has_something<T,decltype(void(&T::DoSomething))> :
std::true_type {};
}
template<template<class> class P,class ...TT>
using sift_t=typename detail::sift<P,pack<TT...>,pack<>,pack<>>::type;
Then decompose the result and inherit from the individual classes:
template<class> struct C;
template<class ...MM,class ...OO> // have Method, Others
struct C<cons<pack<MM...>,pack<OO...>>> : MM...,OO... {
using MM::DoSomething...;
void DoSomething();
};
template<class T> using has_something=detail::has_something<T>;
template<class ...TT> using C_for=C<sift_t<has_something,TT...>>;
Note that the has_something here supports only non-overloaded methods (per base class) for simplicity; see Barry’s answer for the generalization of that.
I am trying to inherit the std::vector class template into my membvec class template as public. And I want to use it as e.g. say membvec<float> mymemb(10) with the intention of creating my membvec variable mymemb containing 10 elements.
But I can't figure out how to write the templatised declaration of the public inheritance. What I am doing is the following, but all in vain.
template <typename T, template <typename T> class std::vector = std::vector<T>>
//error above: expected '>' before '::' token
class membvec: public std::vector<T>
{
const membvec<T> operator-() const; // sorry the previous version was a typo
//error above: wrong number of template arguments (1, should be 2)
...
};
I think you're looking for something like the below, but seriously don't do it. If you ever pass your class as its parent std::vector, there is no virtual interface to allow your class to provide any benefit whatsoever. And if you don't need to substitute for a std::vector then there's no need to inherit from it. Prefer free function algorithms or containing the std::vector as a member in your class instead.
#include <vector>
template <typename T>
class membvec: public std::vector<T>
{
// Don't need <T> in class scope, must return by value.
membvec operator+() const;
};
int main()
{
membvec<int> foo;
}
Perhaps you want something like this:
#include <vector>
template <typename T, template <typename T, class Allocator> class Vec = std::vector>
class membvec: public Vec<T, std::allocator<T>>
{
public:
// This is the signature in your question, but it's questionable.
const membvec<T, Vec> &operator+(int x) const
{
// You obviously want to change this.
return *this;
}
};
You can then use it regularly:
int main()
{
membvec<char> foo;
foo + 3;
}
Problem
Consider the following class
template <typename T>
struct A
{
T x;
};
Now, another class is templated like so:
template <typename T, typename U>
class B
{
protected:
std::vector<U> arr;
public:
T get_x(unsigned int p) { return arr[p].x; }
};
I would like to access the field A<T>::x from within B<T, A<T>>::get_x() and return it unaltered (i.e., keep its type as T). My poor knowledge of templating says that this requires knowing the type andof T it should be one of the template parameters of class B. However, that makes it possible to declare something inconsistent, like B<int, A<double>>, and in general sounds like an unnecessary repetition.
Questions
Is what I wrote an example of bad programming practice? How should this be written?
Is there a possibility of inferring the type T of A<T>::x and avoid two template types? It feels like a repetition, so I am not sure if there is a God-fearing, standard-abiding solution out there or not.
For what it is worth, I am using GCC 4.6.2 with -std=c++0x.
I would suggest an approach adopted by the Standard Library. Define a nested type.
template <typename T>
struct A
{
typedef T value_type; //this is nested type to be used by B
T x;
};
//this is another class added by me, just to demonstrate the genericity
template <typename T>
struct C
{
typedef T value_type; //this is nested type to be used by B
T x;
};
template <typename T>
class B
{
typedef typename T::value_type value_type; //get the nested type
protected:
std::vector<T> arr;
public:
value_type get_x(unsigned int p) { return arr[p].x; }
//^^^^^^^^^ note this
};
Usage:
B<A<int>> ba; //'>>' if C++11, otherwise use '> >' (separate them by space)
B<C<double>> bc; //works for C class template as well
I would like to define a C++ template specialization that applies to all subclasses of a given base class. Is this possible?
In particular, I'd like to do this for STL's hash<>. hash<> is defined as an empty parametrized template, and a family of specializations for specific types:
template<class _Key>
struct hash { };
template<>
struct hash<char>
{
size_t
operator()(char __x) const
{ return __x; }
};
template<>
struct hash<int>
{
size_t
operator()(int __x) const
{ return __x; }
};
...
I would like to define something like this:
template<class Base>
struct hash {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
class Sub : public Base {
public:
size_t my_hash() const { ... }
};
and be able to use it like this:
hash_multiset<Sub> set_of_sub;
set_of_sub.insert(sub);
However, my hash template conflicts with the generic one from STL. Is there a way (perhaps using traits) to define a template specialization that applies to all subclasses of a given base class (without modifying the STL definitions)?
Note that I know I can do this with some extra template parameters whenever this hash specialization is needed, but I'd like to avoid this if possible:
template<>
struct hash<Base> {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
....
// similar specialization of equal_to is needed here... I'm glossing over that...
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub;
set_of_sub.insert(sub);
Since C++ 11 you can use SFINAE together with standard library enable_if and is_base_of to solve the problem.
C++20 makes a cleaner solution possible - basically equivalent to enable_if, which even (optionally) works with CRTP
#include <concepts>
#include <functional>
#include <unordered_set> // just for demo in main()
template <class T>
class Base {};
class Derived final : public Base<Derived> {};
template<class T>
requires std::derived_from<T, Base<T>>
struct std::hash<T> {
// constexpr is optional
constexpr size_t operator() (const T& value) const noexcept {
return 0xDEADBEEF; // FIXME: do something better :)
}
};
int main() {
// If operator() weren't constexpr, this couldn't be a *static* assert
static_assert(std::hash<Derived>()(Derived {}) == 0xDEADBEEF);
std::unordered_set<Derived> usageTest;
return 0;
}
The solution is to use SFINAE to decide whether or not to allow your specialisation depending on the class inheritance structure. In Boost you can use enable_if and is_base_of to implement this.
http://www.boost.org/doc/libs/1_47_0/libs/utility/enable_if.html
http://www.boost.org/doc/libs/1_47_0/libs/type_traits/doc/html/boost_typetraits/reference/is_base_of.html
This was the best I could do:
template<>
struct hash<Sub> : hash<Base> {
};
I'm a little worried that I didn't have to make operator() virtual, though.
I don't think it is possible, because the way to do template specialization based on something more complex than just matching the type is C++ SFINAE, which requires second (dummy) template argument. Unfortunatelly, std::hash takes only one template argument and it is not allowed to create another version of std::hash with two template arguments. Therefore, the if you aren't satisfied with Jayen's solution, you can create your own hash type:
#include <iostream>
#include <type_traits>
using namespace std;
class ParentClass {};
class ChildClass : public ParentClass {};
// SFINAE, if T is not a child of ParentClass, substitution will fail
// You can create specializations for the general case, for another base classes, etc.
template<typename T, typename=typename enable_if<is_base_of<ParentClass, T>::value, T>::type>
struct your_hash
{
size_t operator()(const T& value)
{
return 42;
}
};
int main()
{
ParentClass pc;
ChildClass cc;
cout<<your_hash<ParentClass>()(pc)<<"\n";
cout<<your_hash<ChildClass>()(cc)<<"\n";
}
One of my classes declares a templated function:
template<class A, class B>
A do_something(const std::vector<B> &data)
which I'd like to partially specialize on typename A. B is a family of types that implement a pretty minimal interface, and we use a lot of them, so I'd like my specialization to be generic on B. I suspect this is doubly vexing as typename A is used only as the return type.
From the internet, I've gleaned that I can't partially specialize a function, so I've created a class as follows:
template<class A, class B>
class do_something_implementation {
public:
do_something_implementation(const std::vector<B> &data_) {
data = data_;
}
int do_something_implementation<int, B>::operator()() {
/* Complicated algorithm goes here... */
}
double do_something_implementation<double, B>::operator()() {
/* Different complicated algorithm goes here... */
}
private:
std::vector<B> data;
}
When I try to compile that (using Visual Studio 2008), the compiler crashes (!) and I get the following error:
fatal error C1001: An internal error has occurred in the compiler.
I assume this is my problem and not the compiler's. Is there a better way to express the partial specialization I'm aiming for?
Usually, it goes like this:
template <typename A, typename B>
struct DoSomethingHelper
{
static A doIt(const std::vector<B> &data);
};
template <typename B>
struct DoSomethingHelper<double, B>
{
static double doIt(const std::vector<B> &data) { ... }
};
template <typename B>
struct DoSomethingHelper<int, B>
{
static int doIt(const std::vector<B> &data) { ... }
};
template<class A, class B>
A do_something(const std::vector<B> &data)
{ return DoSomethingHelper<A, B>::doIt(data); }
Now that you've seen the classic forward to static method, there is actually another way when the type for which to specialize is "complete".
You may not be able to partially specialize a function, but you can perfectly overload it.
template <typename A, typename B>
A do(std::vector<B> const& data) { return this->doImpl(data, (A*)0); }
template <typename A, typename B>
A doImpl(std::vector<B> const& B, A*) { // generic implementation }
template <typename B>
int doImpl(std::vector<B> const& B, int*) { // int implementation }
template <typename B>
double doImpl(std::vector<B> const& B, double*) { // double implementation }
The trick is to pass an "unused" argument to doImpl for the sole purpose of actually selecting the right implementation (thanks to overload resolution).
Here I simply chose to pass (A*)0, because this does not involve A's constructor (in case it's non trivial).
This dispatch idiom is what is used in the STL to implement some algorithm with better efficiency for some iterator categories (for example, std::distance is O(1) for random iterators).
I find it much more lightweight that using a helper class with static methods and partial specializations... but maybe that's just me :)
People typically just forward to a static implementation.
template<class A, class B> class X;
template<class A, class B> friend class X;
template<class A, class B> class X {
public:
static A do_something(class_type* not_this, const std::vector<B>& data) {
//...
}
};
// partially specialize
template<class A, class B>
A do_something(const std::vector<B> &data) {
return X<A, B>::do_something(this, data);
};
Not a solution to your problem (there are a couple already there), but some of the things that are wrong in your code:
You are missing a struct or class keyword in the template class declaration:
template <typename A, typename B> struct do_something_implementation {
// ^^^^^^
Inside the class definition, member functions must not use a qualified name, regardless of whether the class is a template or not:
class A {
void A::foo() {} // Error, should be: void foo() {}
};
Member template specializations cannot appear inside the class definition, but at the namespace level:
class B {
template <typename T> void foo( T );
};
template <> void B::foo<int>( int ) {}
template <> void B::foo<double>( double ) {}
Plus on your case, the member function is not a template, but rather a non-templated member function (the template is the containing class, not the function itself). What your code is effectively trying to do is defining other class' member functions inside the general template, kind of trying to do.
Overall there was enough errors to make parsing the code almost impossible for the compiler to identify what you were trying to do and provide a good error message, but still, it should have provided any error message pointing to the first line that you copied instead of chocking to death.