2016-12-30 3 views
2

Я недавно работал над библиотекой C++, где я разрабатывал класс шаблонов, который по соображениям эффективности и безопасности должен был быть специально неполиморфным. Чтобы впоследствии я не забыл об этом и случайно сломал все, я подумал, что буду хорошим гражданином и добавлю статическое утверждение на этот счет.Обеспечение того, что класс шаблонов не является полиморфным?

Первоначально я пытался что-то вроде этого:

template <typename T> class VirtualVerboten { 
    ... 

    static_assert(!std::is_polymorphic<VirtualVerboten>::value, 
        "This should not be polymorphic."); // Error! 
}; 

Это не компилируется, потому что, в то время, что я использую VirtualVerboten, это неполный тип. Если бы это был класс, не шаблон, я бы просто поставить static_assert сразу после типа:

class NonTemplateVirtualVerboten { 
    ... 
} 
static_assert(!std::is_polymorphic<NonTemplateVirtualVerboten>::value, 
       "This should not be polymorphic."); 

Но поскольку это шаблонный класс, аналогичная идея создания «шаблона static_assert» не является юридическим :

template <typename T> class VirtualVerboten { 
    ... 

}; 

template <typename T>    
static_assert(!std::is_polymorphic<VirtualVerboten>::value, 
       "This should not be polymorphic."); // Error! 

решение, которое я придумал было найти функцию члена внутри VirtualVerboten, что, вероятно, будет использоваться, когда шаблон был экземпляр (в частности, конструктор), а затем положить статическое утверждение там:

template <typename T> class VirtualVerboten { 
    VirtualVerboten(); 
}; 

template <typename T> 
VirtualVerboten<T>::VirtualVerboten() { 
    static_assert(!std::is_polymorphic<VirtualVerboten>::value, 
       "This should not be polymorphic."); // Yay! 
    doSomeActualThingsAtRuntime(); 
} 

Это работает, за исключением того, что он полагается на то, что этот конкретный конструктор будет фактически вызван и, следовательно, создан, что не удается, если есть несколько конструкторов, которые можно было бы назвать.

Есть ли «надежный» способ добавить это статическое утверждение здесь? Я понимаю, почему исходный код вызывал ошибку и почему у вас не может быть статического утверждения шаблона, так что это скорее «я пропустил другой способ сделать это?». а не «вот почему то, что вы сделали, не работает».

+0

UHH? Конструктор? Нужно как-то конструировать класс. Наденьте свое статическое утверждение там. –

+0

@SamVarshavchik Вот что я в итоге сделал. Возможно, я должен отредактировать вопрос, чтобы сделать это более ясным. – templatetypedef

+0

Вам просто нужно упаковать тип во что-то зависимое, поэтому статическое утверждение проверяется только во второй фазе. –

ответ

3

Это уже свидетельствует @JerryCoffin's comment. Лучший способ - использовать static_assert в деструкторе. т.е.

template <typename T> 
class VirtualVerboten { 
public: 
    ~VirtualVerboten() { 
    static_assert(!std::is_polymorphic<VirtualVerboten>::value, 
        "This should not be polymorphic."); 
    } 
}; 

Поскольку деструктор может быть только 1, это гарантирует, что static_assert проверяется всякий раз, когда имеется конкретизация его объекта.


IMO, другой элегантный способ создать класс утилиты & унаследовать то же самое, например:

template<typename T> 
struct NonPolymorphic 
{ 
    ~NonPolymorphic() 
    { static_assert(!std::is_polymorphic<T>::value, "This should not be polymorphic."); } 
}; 

template <typename T> 
class VirtualVerboten : NonPolymorphic<VirtualVerboten<T>> 
{ 
    // ... 
}; 
0

Ключевое слово final - это функция C++ 14, которая запрещает унаследовать классы. Если класс наследуется, код не будет компилироваться. Пример:

template <typename T> 
class VirtualVerboten final { 
    ... 
} 

Если кто-то пытается наследовать его ...

class Derived : public VirtualVerboten<int> { 
    ... 
} 

Компилятор пожалуется

+1

Вопрос о полиморфизме, а не наследовании. Правда, эти два очень тесно связаны, но наследование без полиморфизма (т. Е. Использование виртуальных функций) возможно. cppreference описывает свойство типа 'is_polymorphic' как« неединичный класс, который объявляет или наследует хотя бы одну виртуальную функцию ». Это должно дать представление о типах классов, которые OP пытается исключить. –

+0

Как ни странно, в рассматриваемом случае мы используем наследование, но не должны использовать полиморфизм, поэтому этот подход на самом деле не работает в моем случае. – templatetypedef

Смежные вопросы