переменная член-указатель принимается только как аргумент шаблона функции в Clang с -std = c ++ 17 - PullRequest
1 голос
/ 21 апреля 2020

https://godbolt.org/z/o7rBT9

Это прекрасно компилируется в Clang с -std=c++14

struct Vecs
{
    enum class VecIndex { first, second };
    std::vector<int> vec1, vec2;

    template <VecIndex> struct vecForIndex;
    template <> struct vecForIndex<VecIndex::first> {
        static constexpr auto vecPtr = &Vecs::vec1;
    };
    template <> struct vecForIndex<VecIndex::second> {
        static constexpr auto vecPtr = &Vecs::vec2;
    };

    template <std::vector<int> Vecs::*vecPtr>
    static void work() {}

    static void workSpecificVec()  { 
        work<&Vecs::vec1>(); 
    }
};

Но эта версия работы SpecificVe c не делает:

static void workSpecificVec()  { 
    work<vecForIndex<VecIndex::first>::vecPtr>(); 
}

Последний компилируется с -std=c++17.

Почему?

PS Ни g cc, ни msv c не скомпилируют вышеперечисленное с каким-либо стандартом. IIU C явные специализации в области видимости класса были разрешены начиная с c ++ 14 , так что это кажется проблемой либо с компиляторами, либо с моим пониманием.

1 Ответ

2 голосов
/ 21 апреля 2020

Явные специализации в области видимости класса - это функция C ++ 17 ( CWG 727 не была DR по сравнению с C ++ 14, это было новым для C ++ 17), которую g cc просто не делает еще не реализовано (это g cc ошибка 85282 ).

Здесь есть еще одна особенность C ++ 17 - расширение того, какие аргументы можно использовать в качестве нетиповых параметров шаблона ( N4198 для пояснения, N4268 для формулировки). В C ++ 14 vecForIndex<VecIndex::first>::vecPtr не был допустимым нетиповым аргументом шаблона, потому что только допустимые аргументы для указателей на члены (как в вашем примере) были:

  • Точно выражения вида &T::X (например, буквально тот синтаксис)
  • Произвольное константное выражение, которое оценивается как нулевое значение указателя.

И это все. vecForIndex<VecIndex::first>::vecPtr не относится ни к одной из этих вещей, поэтому он плохо сформирован в C ++ 14. В C ++ 17 ограничения на нетипичные параметры шаблонов намного слабее, так что это просто работает.

Если вы хотите, чтобы все это оставалось в теле класса, вы можете использовать шаблон функции с if constexpr вместо специализированного шаблона класса. Это тоже меньше кода:

template <VecIndex I>
constexpr auto vecForIndex()
{
    if constexpr (I == VecIndex::first) return &Vecs::vec1;
    else if constexpr (I == VecIndex::second) return &Vecs::vec2;
}

, а затем:

static void workSpecificVec()  { 
    work<vecForIndex<VecIndex::first>()>(); 
}
...