2012-03-17 2 views
3

Я не совсем уверен, как это объяснить, поэтому, пожалуйста, попросите меня прояснить все, что не имеет смысла. У меня есть интерфейс и шаблонная функция, которая возвращает функцию, которые возвращают анонимные внутренние классы, основанные на время компиляции аргумента:Зачем мне нужен opCmp для анонимного класса?

interface MyInterface { 
    void getName(); 
} 
MyInterface function() getMyInterfaceFactory(string name)() { 
    return function() { 
     return new class MyInterface { 
      void getName() { //Do something involving name here } 
     }; 
    }; 
} 

Теперь getMyInterfaceFactory() имел обыкновение быть getMyInterface() и используются для возврата анонимного объекта непосредственно. Все работало нормально. Когда я добавил фабричные функции, я начал получать исключение при запуске от объекта:

object.Exception.....(102): need opCmp for class mymodule.getMyInterfaceFactory!("someargument").getMyInterfaceFactory.__funcliteral14.__anonclass13 

Итак, я посмотрел на метания линии в источнике druntime, и это выглядит как стандартная реализация opCmp для объекта только броски. Я не сравниваю заводские функции или MyInterface в любом месте. I am 10 am хранения фабрик как значений строкового индексированного ассоциативного массива, но opCmp не требовался, когда я хранили анонимные классы непосредственно в этом массиве, только когда я начал хранить функции. Если я вставляю opCmp (используя адрес памяти), все, кажется, работает нормально, но MyInterface не очень сопоставимо, поэтому я бы предпочел не делать этого, если только не придется. Если возможно, я хотел бы знать, почему/где opCmp вызывается в анонимных классах, и как я могу предотвратить или обойти его.

Примечание: реализация opCmp по умолчанию в объекте включает комментарий, смутно ссылающийся на ошибку, сопоставленное сравнение адресов памяти и затем метательную версию.

Спасибо!

Редактировать: Следует упомянуть, я попробовал как windbg, так и ddbg отслеживать, где именно был вызван opCmp, но в обоих случаях это не удалось. Windbg не дал никакой полезной информации, потому что он упорно отказывался загружать любые символы, ddbg загружены символы, но исключение происходит во время инициализации (после статических конструкторов модуля, но перед основными) и предположительно ddbg не имел доступа к druntime символам?

+0

Я не знаю много о проблеме, но одним обходным решением было бы разместить общую реализацию opCmp в шаблоне mixin (вы можете использовать 'typeof (this)' для вывода типов параметров). Затем вы можете добавить его в свой класс с помощью одной строки кода. –

+0

Хорошо, если я не могу избежать определения opCmp, я, вероятно, попытаюсь свести его к минимуму. Благодаря! – Tim

+0

Почему существует тип возврата void, и вы возвращаете что-то? –

ответ

0

Обновление: У меня возникли проблемы с воспроизведением ошибки opCmp, особенно в примерах игрушек, но я думаю, что я понял, что происходит.
Кажется, что создание анонимных внутренних классов, наследующих интерфейсы внутри анонимных функций, является ошибкой (go figure). В частности, анонимные классы и не очень хорошо относятся к виртуальным функциям. Даже с установленным opCmp у меня были ошибки с toString и конструкторами по умолчанию, и у них были члены, которые просто ничего не делают (но не вызывают или не вызывают при вызове). __traits(allMembers, MyInterface) возвращает ожидаемую информацию, как и __traits(allMembers, typeof(anonInstance)), но вызов часто перечисленных членов не работает. Weird.
Но если я изменил интерфейс на класс с абстрактными методами, ошибка opCmp будет разрешена, анонимный класс будет вести себя так, как ожидалось, и т. Д. Я мало знаю о компиляторах, но я думаю, что во время компиляции таблица символов который сопоставляет имена виртуальных функций адресам памяти, хранящимся в vtbl. Я думаю, что происходит то, что генерируемая карта изменяется при возврате анонимного класса, полученного из интерфейса. Это возможно, потому что интерфейсы поддерживают множественное наследование и поэтому не могут предписывать абсолютное сопоставление vtbl. Однако классы могут требовать, чтобы все наследники придерживались одной и той же схемы сопоставления (я не знаю, если они это делают, но они могут), и поэтому анонимные классы не могут иметь другое сопоставление.
Опять же, я действительно не уверен, но, похоже, это симптом, вызываемый opCmp, хотя я его нигде не использовал. Я не думаю, что это именно проблема opCmp, я думаю, что все виртуальные функции, определенные в Object, уязвимы.Я был в состоянии поддерживать это со следующим:

testopcmphelper.d 
interface TestInterface { 
    string helloWorld(); 
} 
class TestClass { 
    abstract string helloWorld(); 
} 

testopcmp.d 
import testopcmphelper; 
import std.stdio; 

void invokeFn(TestInterface function() f) { 
    auto t = f(); 
    auto s = t.helloWorld(); 
    writeln(s); 
} 

unittest { 
    auto f = function() { 
     return new class TestInterface { 
      string helloWorld() { 
       return "Hello World!"; 
      } 
     }; 
    }; 
    invokeFn(f); 
} 

void invokeFn(TestClass function() f) { 
    auto t = f(); 
    auto s = t.helloWorld(); 
    writeln(s); 
} 

unittest { 
    auto f = function() { 
     return new class TestClass { 
      string helloWorld() { 
       return "Goodbye World!"; 
      } 
     }; 
    }; 
    invokeFn(f); 
} 

который печатает:

src.utilities.testopcmp.__unittest2.__funcliteral1.__anonclass10 
Goodbye World! 

Указав, что invokeFn(TestInterface) звонит Object.toString вместо TestInterface.helloWorld.

Я собираюсь оставить вопрос открытым на другой день, если я допустил ошибку. Я, вероятно, расскажу об этом как об ошибке в DMD. Я буду работать над проблемой, используя только абстрактные классы для анонимных базовых типов фабричных функций. TL; DR Кажется, это ошибка.

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