LINUX.ORG.RU

Будь проклят тот день...[С++ template hell]

 ,


1

4

Портирую код с винды на линукс.

struct CDestroyer
{
...
    template <typename T>
    struct CHelper4
    {
        template <bool a>
        static void delete_data(T& data)
        {
            CHelper2<T>::delete_data<object_type_traits::is_pointer<T>::value>(data);
        }

        template <> // explicit specialization in non-namespace scope ‘struct CDestroyer::CHelper4<T>’
        static void delete_data<true>(T& data) //error: template-id ‘delete_data<true>’ in declaration of primary template

        {
            CHelper3::delete_data(data);
        }
    };

    template <typename T> 
    static void delete_data(T& data)
    {
        CHelper4<T>::delete_data<object_type_traits::is_stl_container<T>::value>(data);
    }
};
Получаю ошибки написанные в комментариях. Гуглинг показал, что частичная спецификация для функций недопустима по стандарту (ну а MSVS традиционно на это кладёт).

Вопрос: как это обойти?

Я в кресты не умею, только в си, так что при ответе пожалуйста учитывайте. Ну или ткните носом в доки, каким образом можно делать условный выбор шаблонов в целом.

★★★★★

Последнее исправление: eagleivg (всего исправлений: 2)

Можно выносить специализацию, как-то так можно попробовать:

struct CDestroyer
{
...
    template <typename T>
    struct CHelper4
    {
        template <bool a>
        static void delete_data(T& data)
        {
            CHelper2<T>::delete_data<object_type_traits::is_pointer<T>::value>(data);
        }
    };

    template <typename T> 
    static void delete_data(T& data)
    {
        CHelper4<T>::delete_data<object_type_traits::is_stl_container<T>::value>(data);
    }
};

template <typename T>
template <>
void CDestroyer::CHelper4<T>::delete_data<true>(T& data)
{
    CHelper3::delete_data(data);
}
xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
#include <cstdio>
#include <cstdint>
#include <string>
#include <iostream>
#include <type_traits>

template <typename T>
struct CHelper4
{
	template <bool a>
	static void delete_data(std::enable_if_t<a, T&> data)
	{
		std::cout << 1 << std::endl;
	}

	template <bool a>
	static void delete_data(std::enable_if_t<!a, T&> data)

	{
		std::cout << 2 << std::endl;
	}
};

int main()
{
	int a = 1;
	CHelper4<int>::delete_data<true>(a);
	CHelper4<int>::delete_data<false>(a);
	return 0;
}
anonymous
()
Ответ на: комментарий от anonymous

можно еще заменить `std::enable_if_t<...>` на `typename std::enable_if<...>::type` для старых компилеров.

anonymous
()
Ответ на: комментарий от xaizek

Вроде это только для классов работает?

    template <typename T>
    struct CHelper4
    {
        template <bool a>
        static void delete_data(T& data)
        {
            CHelper2<T>::delete_data<object_type_traits::is_pointer<T>::value>(data);
        }
    };

    template <typename T>
    static void delete_data(T& data)
    {
        CHelper4<T>::delete_data<object_type_traits::is_stl_container<T>::value>(data);
    }
};

template <typename T>
template <> // error: enclosing class templates are not explicitly specialized
static void CDestroyer::CHelper4<T>::delete_data<true>(T& data)
{
    CHelper3::delete_data(data);
}

eagleivg ★★★★★
() автор топика
Ответ на: комментарий от eagleivg

Да, мой ответ самый лучший. Не слушай прохожих

anonymous
()

Как-то все сложно. Нужен компилятор 17 и что-то подобное должно работать

template<typename T>
void foo()
{
    if constexpr (object_type_traits::is_stl_container<T>::value)
    {
        CHelper3::delete_data(data);
    }
    else
    {
        CHelper2<T>::delete_data<object_type_traits::is_pointer<T>::value>(data);
    }
}
maverik ★★
()
Ответ на: комментарий от anonymous

Спасибо, помогло. Хотя SFINAE всё равно видимо придется изучить.

eagleivg ★★★★★
() автор топика
Ответ на: комментарий от eagleivg

Да, то что оно внутри шаблона всё портит и без SFINAE не получится, видимо.

xaizek ★★★★★
()

ну это разве hell, так.

delete_data просто вынеси из класса и всё.

yoghurt ★★★★★
()
Ответ на: комментарий от Deleted

Да, специализация же. Но работать оно будет только так, что я и забыл:

template <>
template <>

// либо так

template <>
template <bool a>

// обратный порядок нельзя

xaizek ★★★★★
()
Ответ на: комментарий от Deleted

Для случая ТС только SFINAE и будет работать, так как нельзя специализировать член шаблона не специализировав шаблон. Тот второй вариант может делать методы только для специализаций CHelper4:

template <>
template <bool a>
void CHelper4<int>::delete_data(int& data)
{
}

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

То есть, для решения этой конкретно задачи единственный путь — enable_if_t? С частичной спецификацией вне тела класса никак?

Deleted
()
Ответ на: комментарий от Deleted

я чего-то не понимаю, почему вы все говорите про класс? Вроде функция же, в этом и проблема, что её нельзя частично как класс? Или я что-то не знаю?

eagleivg ★★★★★
() автор топика
Ответ на: комментарий от eagleivg

Речь шла об определении функции вне тела структуры (не совсем класса, тут я оговорился). Если совсем просто, выкидывая шаблонную шелуху, речь о следующем:

class MyCls
{
public:
    int sum(int a, int b);
};

int MyCls::sum(int a, int b)
{
    return a + b;
}

Иногда определение вне класса/структуры помогает при частичной спецификации шаблона (если я ничего не путаю. В шаблонах я плох)

Deleted
()
Ответ на: комментарий от Deleted

Автор темы пометил как решенную.

Прошу автора отписаться, вынесение вне класса действительно решило эту проблему? А то тема обрывается и всё.

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от Deleted

Добавил костылей вместо того, чтобы сделать отдельную структуру трейтов :-(

vzzo ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.