简体   繁体   中英

Class template specialization with template template parameters

I am attempting to specialize a class on a type st it ignores the constness of the given type. In this case, the type is a template template parameter:

template <class T, typename Enable = void>
struct bar 
{
    bar()
    {
        static_assert(!std::is_same<T,T>::value, "no implementation of bar for type T");
    }
};

template <template <typename> class FooType, class T>
struct bar<FooType<T>, typename std::enable_if<std::is_same<typename std::remove_cv<FooType<T>>::type, foo<T>>::value>::type>
{};

The above code complains in both GCC 4.8.4 and clang 5.0 (with -std=c++11) that bar is undefined when used with a class matching the template parameterization of FooType. Even if I remove the sfinae parameter, the specialization is still unable to be found.

An example of this issue can be found here: https://godbolt.org/g/Cjci9C . In the above example, the specialization's constructor has a static assert that goes unfound when used with a const FooType, even when the sfinae parameter is hard-coded to void. When used with a non-const FooType all works as expected.

Can someone please provide an explanation as to why the constness prohibits type deduction (matching?) in this context.

EDIT (Updated Code):

Here is a fully compile-able snippet. I tried to capture the minimum example in this snippet. The original link has been updated to reflect this example.

#include <assert.h>
#include <type_traits>

template <class T>
struct foo {};

template <class T, typename Enable = void>
struct bar 
{
    bar()
    {
        static_assert(!std::is_same<T,T>::value, "no implementation of bar for type T");
    }
};

template <template <typename> class FooType, class T>
struct bar<FooType<T>, typename std::enable_if<std::is_same<typename std::remove_cv<FooType<T>>::type, foo<T>>::value>::type>
{};

int main()
{
  bar<foo<int>> mut_foo; // This is fine.
 // bar<const foo<int>> const_foo; // Error. No implementation found.
}

Removing the comment on the 2nd line of main triggers the static assert. I have also tried std::decay, and std::remove_const with no success.

EDIT (Non-duplicate Justification):

While the linked problem does ask a similar problem, it does not require the use of template template parameters. It also only provides a technique for solving the problem and does not justify why the given code snippet does not work. Interestingly that technique does not seem to work with template template parameters, since substituting the following snippet into the above example results in the same error:

template <template <typename> class FooType, class T>
struct bar<FooType<T>,
           typename std::enable_if<std::is_same<FooType<T>, foo<T>>::value || std::is_same<FooType<T>, const foo<T>>::value>::type>
{};

const foo<int> doesn't match FooType<T> ,
it would match const FooType<T> or T (or const T ).

After specialization match, you might add SFINAE:

So, in your case, you may do

template <typename T> struct is_foo : std::false_type {};
template <typename T> struct is_foo<foo<T>> : std::true_type {};


template <class T>
struct bar<T,
           typename std::enable_if<is_foo<typename std::remove_cv<T>::type>::value>::type>
{};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM