struct Bar {
enum { Special = 4 };
};
template<class T, int K> struct Foo {};
template<class T> struct Foo<T,T::Special> {};
Usage:
Foo<Bar> aa;
fails to compile using gcc 4.1.2
It complains about the usage of T::Special for partial specilization of Foo. If Special was a class the solution would be to a typename in front of it. Is there something equivalent to it for enums (or integers)?
Since that is not allowed by C++ as explained by Prasoon, so an alternative solution would be to use EnumToType class template,
struct Bar {
enum { Special = 4 };
};
template<int e>
struct EnumToType
{
static const int value = e;
};
template<class T, class K> //note I changed from "int K" to "class K"
struct Foo
{};
template<class T>
struct Foo<T, EnumToType<(int)T::Special> >
{
static const int enumValue = T::Special;
};
Sample code at ideone : http://www.ideone.com/JPvZy
Or, you can simply specialize like this (if it solves your problem),
template<class T> struct Foo<T,Bar::Special> {};
//usage
Foo<Bar, Bar::Special> f;
The type of a non-type template argument cannot depend on a template parameter of a partial specialization.
ISO C++03 14.5.4/9 says
A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.
template <int I, int J> struct A {};
template <int I> struct A<I+5, I*2> {}; //error
template <int I, int J> struct B {};
template <int I> struct B<I, I> {}; //OK
So something like this is illegal template<class T> struct Foo<T,T::Special> {}; because T::Special depends on T
The usage is also illegal. You have provided one template argument but you need to provide two.
Related
According to the reference, the name of a non-type template parameter is optional, even when assigning a default value (see (1) and (2)). Therefore these template structs are valid:
template <int> struct Foo {};
template <unsigned long = 42> struct Bar {};
I haven't seen a possibility of accessing the values of the non-type parameters.
My question is: What's the point of unnamed/anonymous non-type template parameters? Why are the names optional?
First, we can split declaration from definition.
So name in declaration is not really helpful. and name might be used in definition
template <int> struct Foo;
template <unsigned long = 42> struct Bar;
template <int N> struct Foo {/*..*/};
template <unsigned long N> struct Bar {/*..*/};
Specialization is a special case of definition.
Then name can be unused, so we might omit it:
template <std::size_t, typename T>
using always_t = T;
template <std::size_t ... Is, typename T>
struct MyArray<std::index_sequence<Is...>, T>
{
MyArray(always_t<Is, const T&>... v) : /*..*/
};
or used for SFINAE
template <typename T, std::size_t = T::size()>
struct some_sized_type;
What's the point of unnamed/anonymous non-type template parameters?
I can think of specialization:
template<int = 42>
struct Foo{
char x;
};
template<>
struct Foo<0> {
int x;
};
template<>
struct Foo<1> {
long x;
};
Then:
Foo<0> a; // x data member is int
Foo<1> b; // x data member is long
Foo<7> c; // x data member is char
Foo<> d; // x data member is char
Oh, you can access them!
template <int> struct Foo {};
template <int N>
int get(Foo<N>) {
return N;
}
int main() {
Foo<3> foo;
return get(foo);
}
This might be a bit contrived. But in general for some templates you don't want to name them and then it is convenient that you don't have to.
Unamed type and non-type parameters also allow you to delay type instanciation, using template-template parameters.
Take destination_type in the function below for instance.
It can resolve to any type that has a template-type parameter, and 0 to N template-values parameters.
template <template <typename, auto...> typename destination_type, typename TupleType>
constexpr auto repack(TupleType && tuple_value)
{
return [&tuple_value]<std::size_t ... indexes>(std::index_sequence<indexes...>) {
return destination_type{std::get<indexes>(tuple_value)...};
}(std::make_index_sequence<std::tuple_size_v<TupleType>>{});
}
static_assert(repack<std::array>(std::tuple{1,2,3}) == std::array{1,2,3});
Such mechanic comes handy when you need an abstraction on parameters-pack.
Here, for instance, we do not care if Ts... is a parameter-pack containing multiple arguments, or expand to a single type which itself has multiples template parameters.
-> Which can be transposed from template-type parameters to template-value parameters.
See gcl::mp::type_traits::pack_arguments_as_t
Complete example available on godbolt here.
template <template <typename ...> class T, typename ... Ts>
class pack_arguments_as {
template <template <typename...> class PackType, typename... PackArgs>
constexpr static auto impl(PackType<PackArgs...>)
{
return T<PackArgs...>{};
}
template <typename... PackArgs>
constexpr static auto impl(PackArgs...)
{
return T<PackArgs...>{};
}
public:
using type = decltype(impl(std::declval<Ts>()...));
};
template <template <typename ...> class T, typename ... Ts>
using pack_arguments_as_t = typename pack_arguments_as<T, Ts...>::type;
namespace tests
{
template <typename... Ts>
struct pack_type {};
using toto = pack_arguments_as_t<std::tuple, pack_type<int, double, float>>;
using titi = pack_arguments_as_t<std::tuple, int, double, float>;
static_assert(std::is_same_v<toto, titi>);
static_assert(std::is_same_v<toto, std::tuple<int, double, float>>);
static_assert(std::is_same_v<pack_type<int, double, float>, pack_arguments_as_t<pack_type, toto>>);
}
First of all I'm very sorry for the question title, but it's very hard to describe.
What of those two below is valid syntax if I want to specialized Resolve for all instantiation of A?
1)
template<uint32_t I> struct A {};
template<typename> struct Resolve;
template<uint32_t I>
struct Resolve<A<I>>
{
void f() { printf("im here!\n"); }
};
2)
template<uint32_t I> struct A {};
template<typename> struct Resolve;
template<>
template<uint32_t I>
struct Resolve<A<I>>
{
void f() { printf("im here!\n"); }
};
Or is template<> optional? There's two different answers on SO: here and here.
Also please provide quotation of the standard if possible.
Option 2) doesn't compile on MSVC, but does compile at least on some versions of GCC.
This is correct:
template <uint32_t I>
struct Resolve<A<I>>
{ };
The syntax template <> is used to introduce an explicit specialization (of a class template, function template, whatever) (see [temp.spec]/3 and [temp.expl.spec]/1). But we're trying to do a partial specialization. A partial specialization still needs to introduce template parameters, an explicit specialization does not.
On the other hand, if we were trying to specialize a member of an explicit specialization, then we'd use template <>. For instance:
template <class T>
struct A {
template <class T2> struct B { }; // #1
};
template <> // for A
template <class T2> // for B
struct A<int>::B<T2> { }; // #2
A<char>::B<int> x; // #1
A<int>::B<char> y; // #2
If I have a template class A, like this
template <int n>
class A{
/* some code */
};
Is it possible to have a template class B, that takes a reference or pointer to an A as parameter without having the int n as template parameter in B.
The following code would work:
template <int n, A<n> &a>
class B{
/* some code */
};
But to use this, I always have to supply 2 parameters to B, which would work, but is inconvenient.
In c++17 using auto would work like this
template <auto &a>
class B{
/* some code */
};
But I have to work with the arm-none-eabi-gcc which apparently does not support c++17.
So I'd like to know, if there is any other way of creating such a template, so that B only needs 1 template argument.
If I understood you correctly, the goal is to get the template argument of A and make sure that the type B is instantiated with is actually an A. You can do this with some simple metaprogramming by defining your own type traits for A.
#include <type_traits>
template <int n>
class A {};
template <typename T>
struct is_A : std::false_type {};
template <int m>
struct is_A<A<m>> : std::true_type {
static constexpr int const n = m;
};
template <typename A>
class B {
static_assert(is_A<A>::value,"!");
static constexpr int const n = is_A<A>::n;
};
int main() {
B<A<1>>{};
}
Live example
I have a class that acts as a type trait, returning whether a certain condition is true. It's intended to mark classes as supporting a particular feature.
template <typename T> struct Check : std::false_type { };
I have a template class that contains an inner class:
template <unsigned N>
struct Kitty
{
struct Purr;
};
I want to mark the inner class Purr as supporting the feature denoted as Check. In other words, I want to make it so that Check<Kitty<123>::Purr>::value is true. I tried doing the following, but I get an error:
template <unsigned X>
struct Check<typename Kitty<X>::Purr> : std::true_type { };
error: template parameters not deducible in partial specialization:
Is it possible to accomplish this, or is it a limitation of C++ that you can't specialize on inner template class members?
As outlined in my comment, it is possible to make this a deduced context by using a base class, which I'll call KittyBase. Using a base class is actually common for templates, to avoid having unnecessary code duplicated for every new instantiation. We can use the same technique to get Purr without needing to deduce N.
However, simply putting Purr in the base class will remove its access to N. Fortunately, even in making Purr itself a template, this can still be a non-deduced context: Live example
#include <type_traits>
template <typename T> struct Check : std::false_type { };
struct KittyBase
{
template<unsigned N> // Template if Purr needs N.
struct Purr;
protected:
~KittyBase() = default; // Protects against invalid polymorphism.
};
template <unsigned N>
struct Kitty : private KittyBase
{
using Purr = KittyBase::Purr<N>; // Convenience if Purr needs N.
Purr* meow;
};
template <unsigned X>
struct Check<typename KittyBase::Purr<X>> : std::true_type { };
static_assert(not Check<int>{});
static_assert(Check<Kitty<123>::Purr>{});
static_assert(Check<Kitty<0>::Purr>{});
int main() {}
If you wish, you can even make KittyBase::Purr private and use template<typename T> friend struct Check; to grant access to the trait. Unfortunately, I don't know whether you can limit that to only certain specializations of the trait.
This answer has an interesting approach to finding if a type exists using SFINAE.
Adapted to check if a type T::Purr exists, it allows you to write the type trait without the problematic specialization.
#include <type_traits>
template <unsigned T>
struct Kitty
{
struct Purr{};
};
// A specialization without Purr, to test
template <>
struct Kitty<5>{ };
// has_purr is taken and adapted from https://stackoverflow.com/a/10722840/7359094
template<typename T>
struct has_purr
{
template <typename A>
static std::true_type has_dtor(decltype(std::declval<typename A::Purr>().~Purr())*);
template<typename A>
static std::false_type has_dtor(...);
typedef decltype(has_dtor<T>(0)) type;
static constexpr bool value = type::value;
};
// Check if a type is an instance of Kitty<T>
template<typename T>
struct is_kitty : std::false_type {};
template<unsigned T>
struct is_kitty<Kitty<T>> : std::true_type {};
template <typename T>
struct Check : std::bool_constant< is_kitty<T>::value && has_purr<T>::value> {};
static_assert( Check<int>::value == false, "int doesn't have purr" );
static_assert( Check<Kitty<0>>::value == true, "Kitty<0> has purr" );
static_assert( Check<Kitty<5>>::value == false, "Kitty<5> doesn't has purr" );
I have code with the following structure:
template <typename T>
struct Foo
{
struct Bar
{
int data;
};
};
I want to write metafunctions which will tell me if a type is either Foo or Bar. The first one is easy:
template <typename T>
struct is_foo : boost::mpl::false_
{};
template <typename T>
struct is_foo<Foo<T> > : boost::mpl::true_
{};
...
BOOST_MPL_ASSERT(( is_foo<Foo<int> > ));
BOOST_MPL_ASSERT_NOT(( is_foo<int> ));
However, the same approach does not work for Bar:
template <typename T>
struct is_bar : boost::mpl::false_
{};
template <typename T>
struct is_bar<typename Foo<T>::Bar> : boost::mpl::true_
{};
This code is rejected by the compiler. GCC says:
main.cpp:38:8: error: template parameters not used in partial specialization:
main.cpp:38:8: error: âTâ
Oddly, clang will compile the code, but it issues a warning and the metafunction does not work (always false):
main.cpp:38:8: warning: class template partial specialization contains a template parameter that can not be deduced;
this partial specialization will never be used
struct is_bar<typename Foo<T>::Bar> : boost::mpl::true_
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:37:20: note: non-deducible template parameter 'T'
template <typename T>
^
Is there a workaround for this issue? A c++11-specific solution would be fine.
Here's a hideously inelegant solution to my own question, using TTI (http://svn.boost.org/svn/boost/sandbox/tti):
First, add a dummy tag to Bar:
template <typename T>
struct Foo
{
struct Bar
{
typedef void i_am_bar;
int data;
};
};
Next, use TTI to check for that tag:
BOOST_TTI_HAS_TYPE(i_am_bar);
template <typename T>
struct is_bar : boost::tti::has_type_i_am_bar<T>
{};
...
BOOST_MPL_ASSERT(( is_bar<Foo<int>::Bar> ));
BOOST_MPL_ASSERT_NOT(( is_bar<Foo<int> > ));
BOOST_MPL_ASSERT_NOT(( is_bar<int> ));
Yucky to be sure, but it satisfies my use-case.
The problem is that T is part of the name of the type Foo<T>::Bar, but it's not part of the structure of the type.
A possible solution would be to encode T in the structure of the type:
template<typename Outer, typename Inner> struct Nested: public Inner {
using Inner::Inner;
};
template<typename T> struct Foo {
struct BarImpl {
int data;
};
using Bar = Nested<Foo<T>, BarImpl>;
};
template <typename T> struct is_bar: std::false_type {};
template <typename T, typename U> struct is_bar<Nested<Foo<T>, U>>:
std::is_same<typename Foo<T>::Bar, Nested<Foo<T>, U>> {};
Testing:
static_assert(is_bar<Foo<int>::Bar>::value, "!");
static_assert(!is_bar<Foo<int>>::value, "!");
static_assert(!is_bar<int>::value, "!");
compilers are correct, the simple and easy to understand explanation is: they just don't want to substitute all possible types T just to realise is there a nested type bar inside of given template. More precise explanation you may find in a 'classic' (and well known I hope) book about templates: "C++ Templates - The Complete Guide".
fortunately C++11 helps you to do it even better! :)
#include <type_traits>
template <typename T>
struct has_nested_bar
{
template <typename W>
struct wrapper {};
template <typename C>
static std::true_type check(
const wrapper<C>*
, const typename C::Bar* = nullptr
);
template <class C>
static std::false_type check(...);
constexpr static bool value = std::is_same<
decltype(check<T>(nullptr))
, std::true_type
>::type::value;
typedef std::integral_constant<bool, value> type;
};
this metafucntion would check if a given type has nested Bar type (as far as I understant it was initial purpise of your is_bar).
template <typename T>
struct Foo
{
struct Bar
{
int data;
};
};
struct Bar {};
int main()
{
std::cout << has_nested_bar<Foo<int>>::value << std::endl;
std::cout << has_nested_bar<Bar>::value << std::endl;
return 0;
}
will output:
zaufi#gentop /work/tests $ ./has-nested-bar
1
0
later you may combine this metafunction with your is_foo to check that nested Bar actually is inside of a Foo...