If I have a templated struct as such:
template<typename T>
struct A {};
How can I remove the partial specialization for a certain type, such as void so that any mention of A< void > will give a compiler error?
template<>
struct A<void> = delete;
This doesn't compile as is expected as this syntax doesn't exist, although I'd essentially want something similar to this.
Although I do currently have a 'solution' to this problem, which is to delete all possible constructors:
template<>
struct A<void> { template<typename...> A(...) = delete; };
But this isn't the best solution as the user can still use A< void > as long as they don't try to instantiate an object. I've also tried to add an enable_if to the initial structure as such:
template<typename T, typename = typename std::enable_if<!std::is_same<T, void>::value>::type>
struct A {};
This works well, it makes it so the mention of A< void > gives a compiler error (Although somewhat criptic, since it refers to the enable_if itself), but this doesn't work if I don't have access to the initial definition such as when specializing someone else's structure.
So is there any good way to do this aside from the solution I have so far, and if not, is there a way to improve the one I have to give a compiler error when the user uses A< void >?
I can use c++17 and clang's c++2a if it adds any new features that would help with this.
Update: As @PicaudVincent said in his answer, the second solution wouldn't allow you to restrict all types based on a condition, only single types, but there is a way around it:
We could write a perfect wrapper around our struct A, that is, a wrapper that behaves exactly like the original type with the help of a Helper function
template<template<typename...> class U, typename=void, typename...TArgs>
struct Helper : U<TArgs...>
{
using U<TArgs...>::U;
template<typename...Args>
Helper(Args...args) : U<TArgs...>(args...) {};
};
template<typename...Args>
using B = Helper<A,
typename std::enable_if<(... && std::is_arithmetic<Args>::value)>::type,
Args...>;
And now you can use B<> instead of A<>, even though they are the same thing and will behave in the same way and will get converted to A<> whenever needed, such as when calling a function that takes in A<>.
Although if a function takes in B<>, you cannot pass A<> unless you explicitly convert the A<> to B<> with static_cast or similar.
This also works for any templated class, you have just to substitute A for the class you're trying to use and the enable_if with your condition as such:
using B = Helper</*Structure to use*/,
typename std::enable_if</*Condition*/>::type,
Args...>;
This isn't the best solution, but it does allow you to now have to change the original declaration and still restrict what you can put in there without having to name each type manually.