2017-01-15 1 views
4

Я пытаюсь найти хороший способ удалить устаревшие классы из моей библиотеки, сохраняя при этом хорошие сообщения об ошибках. Эта идея основана на чем-то я уже делать с функциями:Как удалить классы при сохранении предупреждений об отставке

namespace 
{ 
    [[deprecated("This function has been replaced by combust()")]] 
    void explode() = delete; // Using variadic templates in reality to have all signatures covered 

    void combust() {} 
} 

int main() 
{ 
    explode(); 
    combust(); 
} 

В лязгом, это дает мне хорошее сообщение об ошибке:

<source>:11:2: error: call to deleted function 'explode': This function has been replaced by combust() 
explode(); 
^~~~~~~ 

НКУ только дает мне только сообщение, что эта функция была удалена , Хотя, это все еще показывает намерение для всех, кто пытается обновить библиотеку, которая игнорирует предупреждение об устаревании.

Итак, поскольку это библиотека C++, у меня в основном есть классы, и я ищу правильный способ сделать что-то подобное с этими классами. Мой текущий подход выглядит следующим образом:

namespace 
{ 
    class [[deprecated("Class has been replaced by Bar")]] Foo 
    { 
     Foo() = delete; // And every other method I had in this class 
    }; 
    class Bar 
    { 
    }; 
} 

int main() 
{ 
    Foo f; 
    Bar b; 
} 

В основном это дает мне следующие предупреждения/ошибки в звоне (и аналогичном в НКУ):

<source>:13:5: warning: 'Foo' is deprecated: Class has been replaced by Bar [-Wdeprecated-declarations] 
Foo f; 
^ 
<source>:3:60: note: 'Foo' has been explicitly marked deprecated here 
class [[deprecated("Class has been replaced by Bar")]] Foo 
^ 
<source>:13:9: error: call to deleted constructor of '(anonymous namespace)::Foo' 
Foo f; 
^ 
<source>:5:8: note: 'Foo' has been explicitly marked deleted here 
Foo() = delete; 
^ 

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

Итак, что я ищу, это хороший способ сделать следующее: (без компиляции кода)

class [[deprecated("Class has been replaced by Bar")]] Foo = delete; 

Замкнутый я попал в Oneliner является:

struct [[deprecated("Class has been replaced by Bar")]] Foo { Foo() = delete; }; 
struct [[deprecated("Class has been replaced by Bar")]] Foo; 

Обратите внимание, что не распространяется на случаи, когда Foo передается по ссылке, и вызываются некоторые методы.

Есть ли у кого-нибудь лучшее решение для удаления классов при наличии явных предупреждений об устаревании для некоторых из следующих выпусков?

+1

Я думаю, вы используете неправильные термины. «Устаревший» должен * никогда * означать «нефункциональный». [[устарело]] следует применять только к методам и классам *, которые работают *. Устаревание - это признак того, что, пока это работает * прямо сейчас *, он может быть удален * позже. Вы никогда не должны удалять функции/классы, а затем маркировать их [[устарело]]. Просто удалите их; компилятор позволит пользователям классов/функций знать, что они скоро ушли;) –

+0

@NicolBolas Как объяснялось, это второй шаг, облегчающий миграцию для тех, кто игнорирует предупреждения об устаревании. И для функций люди из Clang считают его хорошей идеей, поскольку у них даже есть конкретное сообщение об ошибке, чтобы объединить эти два. – JVApen

+0

"и некоторые методы называются" - как методы называются 'class Foo {Foo() = delete; } 'точно? – Yakk

ответ

1

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

template <int I = 0> 
void explode() 
{ 
    static_assert(I && false, "This function has been replaced by combust()"); 
} 

int main() 
{ 
    // error: static_assert failed: "This function has been replaced by combust()" 
    explode(); 
} 

Это также может быть использовано для занятий. Тем не менее, необходимо использовать typedef, поскольку требуются аргументы шаблона.

namespace 
{ 
    template <int I = 0> 
    class FooDeprec 
    { 
     static_assert(I && false, "Class has been replaced by Bar"); 

     FooDeprec() = default; // no need to delete 
    }; 

    using Foo = FooDeprec<>; 
} 

int main() 
{ 
    // error: static_assert failed "Class has been replaced by Bar" 
    Foo f; 
} 

Преимущество этого в том, что не требуется больших изменений - вы можете хранить декларации функций-членов.

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