Prevent templated class from using itself as instance - c++

Suppose I have a class template
template<class T>
class Foo{};
Is it possible to prevent T from being an instantiation of Foo. That is, this should not compile:
struct Bar{};
Foo<Foo<Bar>> x;

Another option:
#include <type_traits>
template <typename T>
struct ValidFooArg;
template <typename T>
requires ValidFooArg<T>::value
class Foo
{
};
template <typename T>
struct ValidFooArg : std::true_type {};
template <typename T>
struct ValidFooArg<Foo<T>> : std::false_type {};
int main()
{
Foo<int> x; // ok
Foo<Foo<int>> y; // error
}

You might still provide partial specialization to have error in that case:
template <typename T>
constexpr bool always_false = false;
template<class T>
class Foo<Foo<T>>
{
static_assert(always_false<T>);
};

Related

Check if a type is the same as a templated type

I have a user defined class
template<typename T, int N>
class MyClass
{
// Implementation
};
and I want to check on the instantiation of another class if its template parameter is an instance of MyClass
template<typename T, std::enable_if_t<!is_MyClass<T>, bool> = true>
class MapClass
{
// custom stuff here
};
template<typename T, std::enable_if_t<is_MyClass<T>, bool> = true>
class MapClass
{
// Some more stuff here
};
I tried to implement it like this but my instantiation fails because it requires two parameters. How do I make automatically extract both parameters
template <typename T> struct is_MyClass : std::false_type {};
template <typename T, int N> struct is_MyClass<MyClass<T, N>> : std::true_type {};
Thanks
I suggest to write a trait is_instantiation_of_myClass that uses partial specialization:
template<typename T, int N>
class MyClass {};
template <typename C>
struct is_instantiation_of_myClass : std::false_type {};
template <typename T,int N>
struct is_instantiation_of_myClass<MyClass<T,N>> : std::true_type {};
template <typename C>
constexpr bool is_instantiation_of_myClass_v = is_instantiation_of_myClass<C>::value;
Now you can do SFINAE based on is_instantiation_of_myClass<T> or just plain specialization:
template <typename T,bool = is_instantiation_of_myClass_v<T>>
struct Foo;
template <typename T>
struct Foo<T,true> {
static constexpr bool value = true;
};
template <typename T>
struct Foo<T,false> {
static constexpr bool value = false;
};
int main() {
std::cout << Foo< int >::value << "\n";
std::cout << Foo< MyClass<int,42>>::value << "\n";
}
Live Demo

How to implement partial specialized template on void separate from definition?

I have a problem in separating the implementations of an inner class while having partial specializations. Here is a sample code that illustrate my problem:
#include <type_traits>
template <typename T>
using enable_if_copyable = std::enable_if_t<std::is_copy_constructible<T>::value>;
template <typename T>
using enable_if_not_copyable = std::enable_if_t<!std::is_copy_constructible<T>::value>;
template <typename T, typename Enabled=void>
struct Foo;
template <typename T>
struct Foo<T, enable_if_copyable<T>>
{
struct Bar
{
Bar();
};
};
template <typename T>
struct Foo<T, enable_if_not_copyable<T>> {
struct Bar
{
Bar();
};
};
template <>
struct Foo<void,void>
{
struct Bar
{
Bar();
//Bar() {} This compiles, but it is not what I want.
};
};
template <typename T>
Foo<T, enable_if_copyable<T>>::Bar::Bar()
{}
template <typename T>
Foo<T, enable_if_not_copyable<T>>::Bar::Bar()
{}
template <>
Foo<void, void>::Bar::Bar() // this does not compile
{}
int main() {
Foo<int>::Bar b;
Foo<void>::Bar v;
}
Because of dependencies I have to implement the c'tors of Bar outside their declaration.
My problem is that all compiler (Clang, gcc, Visual Studio 2015) complain about the implementation of Foo<void, void>::Bar::Bar() {} outside of the declaration of class Foo<void, void>. If I implement the c'tor of Bar inside the specialization on void, I don't have any problem.
Is this is not doable or is there one who could help me to spot my problem?
Many thanks in advance!
Try deleting the template<>; i mean:
// template <>
Foo<void, void>::Bar::Bar() // now compile
{}
See this page for further details.

template of template syntax

I am at a bit of a loss with templates of templates.
#include <iostream>
template <class T>
class Foo{
T foobar;
T getFooBar();
};
template <class T>
T Foo<T>::getFooBar(){
return (T) 2.0;
}
template <class T, template<class> class H>
class Bar{
void barbar();
};
template <class T, template<class> class H>
void Bar<T, H<T> >::barbar(){}
int main(int iargc, char *iargv[]){
// do stuff;
}
This does not compile and I do not understand the error message of the compiler
expected a class template, got ‘H<T>’
The correct syntax would be to just pass H:
template <class T, template<class> class H>
void Bar<T, H>::barbar() {}
^^
H<T> is a concrete type, H by itself is the class template you're looking for.
H<T> is itself a type, so you don't need to prefix template<class> to the template parameter for Bar.
Here is a simplified example:
template<class A>
class T1 {
A a;
};
template<class B>
class T2 {
B a;
};
class T3 {
T1<T2<int> > example;
};
If you want to define the member function barbar(), you should
template <class T, template<class> class H>
void Bar<T, H>::barbar(){
// use the type H<T> here
};

Correct usage of C++ template template parameters

I've some trouble to make use of template template parameters. Here is a very simplified example:
template <typename T>
struct Foo {
T t;
};
template <template <class X> class T>
struct Bar {
T<X> data;
X x;
};
int main()
{
Bar<Foo<int>> a;
}
The compiler (g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2) reports the following error:
main.cpp:8:5: error: ‘X’ was not declared in this scope
T<X> data;
^
main.cpp:8:6: error: template argument 1 is invalid
T<X> data;
^
Any idea what's wrong?
So I would like so make use of something like Bar<Foo<>>
template <typename T = int>
struct Foo {
T t;
};
template <typename T>
struct Baz {
T t;
};
template <typename T>
struct Bar;
template <template <typename> class T, typename X>
struct Bar<T<X>> {
T<X> data;
X x;
};
int main()
{
Bar<Foo<>> a;
Bar<Baz<float>> b;
}
template <typename T>
struct Foo {
T t;
};
template <template <class> class T, class X>
struct Bar {
T<X> data;
X x;
};
int main()
{
Bar<Foo, int> a;
}
In
template <template <class X> class T>
The template type parameter X is not a template parameter to the outermost template: it is a template parameter to the innermost template. It's rather similar to
int foo(int (*bar)(int x))
{
int y = x; // compiler error
}
which doesn't work since the function takes a single argument, bar: there is no argument x.
Depending upon what you are truly trying to do, you could add the second template parameter, with something like
template <typename X, template <typename> class T >
struct Bar
{
// ...
};
you can keep the declaration with a single type parameter, but pattern match to give a partial specialization that would define the class in the example context
template <typename T>
struct Bar;
template <typename X, template <typename> class T >
struct Bar<T<X>>
{
// ...
};
you could modify Foo to have a useful nested type, and grab it that way
template <typename T>
struct Bar
{
using X = T::value_type;
};
or you could define a metafunction that extracts a template parameter from a template type, and get it that way:
template <typename T>
struct Bar
{
using X = get_parameter<T>;
};
The most flexible is the last version, except rather than a metafunction that extracts template arguments, you would declare a get_bar_parameter function, and define a partial specialization that extracts the template parameter from a Foo<X> (or a T<X>). That way, if you ever decide in the future to use Bar with classes where the right value of X isn't computed that way, you can do so by giving an appropriate specialization for get_bar_parameter.
// method 1
template <typename T>
struct Foo {
typedef T Type;
T t;
};
template <typename T>
struct Bar {
T data;
typename T::Type x;
};
// method 2
template <typename T>
struct Hack
{
T t;
};
template <typename T>
struct TypeOf
{
typedef struct UnknownType Type;
};
template<>
struct TypeOf< Hack<int> >
{
typedef int Type;
};
template <typename T>
struct Baz {
T data;
typename TypeOf<T>::Type X;
};
int main()
{
Bar< Foo<int> > a;
Baz< Hack<int> > b;
return 0;
}
In method 1 information is provided with nested type. This requires changing original class.
In method 2 this information is provided with specialization of another template.

Fixed number of template arguments from a variadic template

template <template <typename> class F> struct call_me {};
template <typename T> struct maybe;
template <typename... T> struct more;
int main()
{
call_me<maybe> a; // ok
call_me<more> b; // error
}
I understand why call_me<more> fails. But I want to make it work.
Is there a workaround that doesn't involve changing call_me (or add an specialization to it)?
template <template <typename> class F> struct call_me {};
template <typename T> struct maybe;
template <typename... T> struct more;
template <template <class...> class F> struct just_one {
template <class A> using tmpl = F<A>;
};
int main()
{
call_me<maybe> a;
call_me<just_one<more>::tmpl> b;
}
Not exactly equivalent, but maybe close enough.
template <typename T> using onemore = more<T>;
int main()
{
call_me<onemore> b;
}
You could wrap more:
template <template <typename...> class Tmpl>
struct variwrap
{
template <typename> struct Dummy
{
template <typename ...Brgs>
struct rebind
{
typedef Tmpl<Brgs...> other;
};
};
};
Now you can say call_me<variwrap<more>::Dummy>, and the consumer can use F::rebind<Args...>::other to recover more<Args...>. Of course call_me has no way of knowing that F has the rebind member, so you'll need to add a specialization.
Yuck.