Можно ли заставить шаблоны выбирать альтернативную исходную строку, если исходная исходная строка не компилируется? - PullRequest
1 голос
/ 24 июня 2011

Я ищу относительно общий:

  1. , попробуйте скомпилировать эту строку кода
  2. , если это удастся, скомпилируйте и используйте эту строку кода.В противном случае
  3. используйте другую строку кода

У меня есть случай, когда я хотел бы выборочно скомпилировать что-либо, основываясь на том, допустим ли поставленный функтор на double s.:

//Some user supplied functor I can't modify which works on `int` but not `double`
template<typename T>
struct LShift : std::binary_function<T, T, T>
{
    T operator()(T lhs, T rhs)
    {
        return lhs << rhs;
    }
};

//Class that holds either an int or a double
class Example
{
    union
    {
        int intVal;
        double dblVal;
    } value;
    bool isIntType;
public:
    Example(int val)
        : isIntType(true)
    {
        value.intVal = val;
    }
    Example(double val)
        : isIntType(false)
    {
        value.dblVal = val;
    }
    int GetIntergalValue() const
    {
        return value.intVal;
    }
    double GetDoubleValue() const
    {
        return value.dblVal;
    }
    bool IsIntegral() const
    {
        return isIntType;
    }
};

//Does something with an example. I know that if the examples have `double` contents,
//that the functor passed will also be valid for double arguments.
template <template <typename Ty> class FunctorT>
Example DoSomething(const Example& lhs, const Example& rhs)
{
    if (lhs.IsIntergal() != rhs.IsIntergal())
    {
        throw std::logic_error("...");
    }
    if (lhs.IsIntegral())
    {
        return Example(FunctorT<int>(lhs.GetIntergalValue(), rhs.GetIntergalValue()));
    }
    else
    {
        return Example(FunctorT<double>(lhs.GetDoubleValue(), rhs.GetDoubleValue()));
    }
}


int main()
{
    DoSomething<LShift>();
}

Я никогда раньше не использовал SFINAE, но это была моя первая попытка:

template <template <typename Ty> class FunctorT>
double DoDouble(double lhs, double rhs)
{
    return FunctorT<double>()(lhs, rhs);
}

template <template <typename Ty> class FunctorT>
double DoDouble(int lhs, int rhs)
{
    throw std::logic_error("That is not valid on floating types.");
}

Я думал, что замена не удастся при первой перегрузке (которая будет выбрана, потому что этолучшая перегрузка при передаче удваивается), и этот контроль затем переходит ко второй перегрузке.Тем не менее, все это не компилируется в любом случае.

То, что я пытаюсь сделать разумным или возможным?

1 Ответ

2 голосов
/ 24 июня 2011

Попробуйте (это не так, может иметь синтаксические ошибки):

template < class Type >
Type ShiftLeft( Type lhs, Type rhs )
{
    return LShift( lhs, rhs );
}

template <>
double ShiftLeft( double lhs, double rhs )
{
    assert( "ShiftLeft is not valid on floating types." && false );
    return 0;
}

В качестве альтернативы вы можете использовать SFINAE через Boost enable_if.

Но в этом есть сильный запах. Код, где специализация не вызывается (!), Скорее всего, должен быть реорганизован. В некотором роде.

Приветствия и hth.,

...