В настоящее время я пишу программу, работающую с NURBS surfaces
где вы можете выполнять алгоритмы в двух направлениях (U
а также V
). Чтобы избежать дублирования кода, я пытался использовать шаблоны, но я ни в коем случае не имел опыта их использования. Вот небольшой пример того, что я хотел бы сделать:
#include <iostream>
enum class Dir {
U, V
};
struct Foo {
unsigned cu, cv;
Foo(unsigned cu, unsigned cv) : cu(cu), cv(cv) {};
template<Dir>
const Dir otherDir();
template<>
const Dir otherDir<Dir::V>() {
return Dir::U;
}
template<>
const Dir otherDir<Dir::U>() {
return Dir::V;
}
template<Dir>
unsigned count();
template<>
unsigned count<Dir::U>() {
return cu;
}
template<>
unsigned count<Dir::V>() {
return cv;
}
template<Dir d>
unsigned totalCount() {
auto c = count<d>();
auto cOther = count<otherDir<d>()>();
return c * cOther;
}
};
int main() {
Foo f(3,2);
std::cout << (f.count<Dir::U>() == 3) << std::endl;
std::cout << (f.otherDir<Dir::U>() == Dir::V) << std::endl;
std::cout << f.totalCount<Dir::U>() << std::endl;
}
но это не компилируется из-за последней строки в main (VS2015, но я не думаю, что это ошибка компилятора):
1>...\main.cpp(42): error C2672: 'Foo::count': no matching overloaded function found
1>...\main.cpp(52): note: see reference to function template instantiation 'unsigned int Foo::totalCount<Dir::U>(void)' being compiled
1>...\main.cpp(42): error C2975: 'unnamed-parameter': invalid template argument for 'Foo::count', expected compile-time constant expression
1>...\main.cpp(27): note: see declaration of 'unnamed-parameter'
1>...\main.cpp(43): error C3536: 'cOther': cannot be used before it is initialized
Единственный способ приблизиться к описанной выше функциональности — это указать как основное направление, так и другое направление в качестве аргументов шаблона следующим образом:
struct Foo {
...
template<Dir d, Dir otherD>
unsigned totalCount() {
auto c = count<d>();
auto cOther = count<otherD>();
return c * cOther;
}
};
int main() {
Foo f(3,2);
std::cout << f.totalCount<Dir::U, Dir::V>() << std::endl;
}
но это не кажется очень элегантным.
otherDir<d>()
не является constexpr
и не может использоваться в аргументе шаблона (count<otherDir<d>()>()
).
Вы можете добавить constexpr
(а также static
) к этому методу,
или используйте старую структуру для обработки этого:
template <Dir> struct otherDir;
template<>
struct otherDir<Dir::U>
{
static constexpr Dir value = Dir::V;
};
template<>
struct otherDir<Dir::V>
{
static constexpr Dir value = Dir::U;
};
Возможно, проблема здесь:
auto cOther = count<otherDir<d>()>();
Шаблоны «разрешаются» во время компиляции. Вы должны использовать constexpr
за otherDir<d>()
потому что просто const
не означает, что метод может быть оценен во время компиляции.
Более традиционный подход — иметь структуру otherDir
вместо метода. Создайте шаблон структуры, два экземпляра будут с static const value = V
или же U
,
Или вы можете заменить enum на пустые структуры.
Или, что еще лучше, вы можете попробовать реализовать его без шаблонов и создать класс для измерения и иметь один объект для каждого измерения.