I have a template class/struct that looks like this:
template <typename T, typename U>
struct S
{
unsigned int operator()(T t, U u) const;
};
And I would like to make sure that specializations respect this interface.
Unfortunately, I can specialize this struct with a different return type. For instance if I partial-specialize to return bool
instead of unsigned int
, I would expect to get a compiler error, but the compiler does not seem to care:
template <typename T>
struct S<T,nullptr_t>
{
bool operator()(T t, nullptr_t u) const { return 2; }
};
Example @ Ideone.com
In the above example, the specialized version is supposed to return 2
but since the return type is bool
, the return value is converted to true
which is then displayed as 1
.
Why does the compiler accept this?
How can I prevent programmers from specializing the template with a wrong return type (or even with wrong arguments)?
I know I can achieve what I want with a virtual method in a base template class/struct and use the override
keyword in children:
Solution with override (does not compile, which is good)
But having a virtual method will certainly create a virtual table and I would like to avoid that as much as possible, especially since I do not need the virtual table at run-time. Unless there is a trick to do the same without building a virtual table?
Also, I know the problem would be simpler if I could partial-specialize methods or if I could rely on non-partial-specialization, but the former is not possible in C++ AFAIK and the latter does not cover the case I need in my program.
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.
To do so, we can use a function template specialization (sometimes called a full or explicit function template specialization) to create a specialized version of the print() function for type double.
You cannot define a virtual template method. override only works for virtual methods, and you can only override methods with the same signature.
What Does Template Mean? A template is a C++ programming feature that permits function and class operations with generic types, which allows functionality with different data types without rewriting entire code blocks for each type.
A good way to create static interface is usage of curiously recurring template pattern. In Your situation it would look like this:
template<class Derived, class T, class U>
constexpr bool MyTrait = std::is_same<unsigned int, decltype(std::declval<Derived>()(std::declval<T>(), std::declval<U>()))>::value;
template <typename Derived, class T, class U>
struct StaticInterface
{
unsigned int operator()(T t, U u) const{
static_assert( MyTrait<Derived, T, U>, "errr" );
return (*static_cast<const Derived *>(this))(std::forward<T>(t), std::forward<U>(u));
}
};
template <typename T, typename U>
struct S : StaticInterface<S<T, U>, T, U>
{
unsigned int operator()(T t, U u) const{ /* some implementation */}
};
template <typename T>
struct S<T, std::nullptr_t> : StaticInterface<S<T, std::nullptr_t>, T, std::nullptr_t>
{
bool operator()(T t, std::nullptr_t u) const { return 2; }
};
To get it working the function call must be done via interface like this:
template<class Derived, class T, class U>
void test(const StaticInterface<Derived, T, U> &inter){
inter(T(), U());
}
Otherwise the operator from derived will be picked as the preferable one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With